{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 自动编码器\n",
    "自动编码器最开始是作为一种数据压缩方法，同时还可以在卷积网络中进行逐层预训练，但是随后更多结构复杂的网络，比如 resnet 的出现使得我们能够训练任意深度的网络，自动编码器就不再使用在这个方面，下面我们讲一讲自动编码器的一个新的应用，这是随着生成对抗模型而出现的，就是使用自动编码器生成数据。\n",
    "\n",
    "自动编码器的一般结构如下\n",
    "\n",
    "![](https://ws1.sinaimg.cn/large/006tNc79ly1fmzr05igw3j30ni06j3z4.jpg)\n",
    "\n",
    "由上面的图片，我们能够看到，第一部分是编码器(encoder)，第二部分是解码器(decoder)，编码器和解码器都可以是任意的模型，通常我们可以使用神经网络作为我们的编码器和解码器，输入的数据经过神经网络降维到一个编码，然后又通过另外一个神经网络解码得到一个与原始数据一模一样的生成数据，通过比较原始数据和生成数据，希望他们尽可能接近，所以最小化他们之间的差异来训练网络中编码器和解码器的参数。\n",
    "\n",
    "当训练完成之后，我们如何生成数据呢？非常简单，我们只需要拿出解码器的部分，然后随机传入 code，就可以通过解码器生成各种各样的数据\n",
    "\n",
    "![](https://ws3.sinaimg.cn/large/006tNc79ly1fmzrx3d3ygj30nu06ijs2.jpg)\n",
    "\n",
    "下面我们使用 mnist 数据集来说明一个如何构建一个简单的自动编码器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T10:09:21.223959Z",
     "start_time": "2018-01-01T10:09:20.758909Z"
    },
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "import torch\n",
    "from torch.autograd import Variable\n",
    "from torch import nn\n",
    "from torch.utils.data import DataLoader\n",
    "\n",
    "from torchvision.datasets import MNIST\n",
    "from torchvision import transforms as tfs\n",
    "from torchvision.utils import save_image"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "进行数据预处理和迭代器的构建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T10:09:21.368959Z",
     "start_time": "2018-01-01T10:09:21.341312Z"
    },
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "im_tfs = tfs.Compose([\n",
    "    tfs.ToTensor(),\n",
    "    tfs.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) # 标准化\n",
    "])\n",
    "\n",
    "train_set = MNIST('./mnist', transform=im_tfs)\n",
    "train_data = DataLoader(train_set, batch_size=128, shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T10:09:23.526707Z",
     "start_time": "2018-01-01T10:09:23.489417Z"
    },
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 定义网络\n",
    "class autoencoder(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(autoencoder, self).__init__()\n",
    "        \n",
    "        self.encoder = nn.Sequential(\n",
    "            nn.Linear(28*28, 128),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(128, 64),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(64, 12),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(12, 3) # 输出的 code 是 3 维，便于可视化\n",
    "        )\n",
    "        \n",
    "        self.decoder = nn.Sequential(\n",
    "            nn.Linear(3, 12),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(12, 64),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(64, 128),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(128, 28*28),\n",
    "            nn.Tanh()\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        encode = self.encoder(x)\n",
    "        decode = self.decoder(encode)\n",
    "        return encode, decode"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里定义的编码器和解码器都是 4 层神经网络作为模型，中间使用 relu 激活函数，最后输出的 code 是三维，注意解码器最后我们使用 tanh 作为激活函数，因为输入图片标准化在 -1 ~ 1 之间，所以输出也要在 -1 ~ 1 这个范围内，最后我们可以验证一下"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T10:09:26.677033Z",
     "start_time": "2018-01-01T10:09:26.657447Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([1, 3])\n"
     ]
    }
   ],
   "source": [
    "net = autoencoder()\n",
    "x = Variable(torch.randn(1, 28*28)) # batch size 是 1\n",
    "code, _ = net(x)\n",
    "print(code.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到最后得到的 code 就是三维的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T10:09:27.739067Z",
     "start_time": "2018-01-01T10:09:27.726089Z"
    },
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "criterion = nn.MSELoss(size_average=False)\n",
    "optimizer = torch.optim.Adam(net.parameters(), lr=1e-3)\n",
    "\n",
    "def to_img(x):\n",
    "    '''\n",
    "    定义一个函数将最后的结果转换回图片\n",
    "    '''\n",
    "    x = 0.5 * (x + 1.)\n",
    "    x = x.clamp(0, 1)\n",
    "    x = x.view(x.shape[0], 1, 28, 28)\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T11:03:15.048160Z",
     "start_time": "2018-01-01T10:09:28.323220Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 20, Loss: 109.0523\n",
      "epoch: 40, Loss: 95.4651\n",
      "epoch: 60, Loss: 89.8394\n",
      "epoch: 80, Loss: 107.5620\n",
      "epoch: 100, Loss: 92.2142\n"
     ]
    }
   ],
   "source": [
    "# 开始训练自动编码器\n",
    "for e in range(100):\n",
    "    for im, _ in train_data:\n",
    "        im = im.view(im.shape[0], -1)\n",
    "        im = Variable(im)\n",
    "        # 前向传播\n",
    "        _, output = net(im)\n",
    "        loss = criterion(output, im) / im.shape[0] # 平均\n",
    "        # 反向传播\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "    \n",
    "    if (e+1) % 20 == 0: # 每 20 次，将生成的图片保存一下\n",
    "        print('epoch: {}, Loss: {:.4f}'.format(e + 1, loss.data[0]))\n",
    "        pic = to_img(output.cpu().data)\n",
    "        if not os.path.exists('./simple_autoencoder'):\n",
    "            os.mkdir('./simple_autoencoder')\n",
    "        save_image(pic, './simple_autoencoder/image_{}.png'.format(e + 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "训练完成之后我们可以看看生成的图片效果\n",
    "\n",
    "![](https://ws2.sinaimg.cn/large/006tNc79ly1fmzw2c26qtj306q0a2abh.jpg)\n",
    "\n",
    "可以看出，图片还是具有较好的清晰度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T11:03:21.396147Z",
     "start_time": "2018-01-01T11:03:19.489154Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAcUAAAE1CAYAAACWU/udAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzsnXmcXHWZ7p9TS9feWzqd7nSS7vSS\ndHcWspIEEVAvjIiCgsIwOEEFUe7gIMhonKsojmKcuSgjzJ1xiQrODA53roKguAszLCERkpBASLqr\nqvdO9V77es65f3TO4VTVOVVnq1PVXb/v58OHdFWdpbq6znPe9/e+z0uxLAsCgUAgEAiAqdwnQCAQ\nCARCpUBEkUAgEAiE8xBRJBAIBALhPEQUCQQCgUA4DxFFAoFAIBDOQ0SRQCAQCITzEFEkEAgEAuE8\nRBQJBAKBQDgPEUUCgUAgEM5jUfh6Yn9DIBAIhKUIJedFJFIkEAgEAuE8RBQJBAKBQDgPEUUCgUAg\nEM5DRJFAIBAIhPMQUSQQCAQC4TxEFAkEAoFAOA8RRQKBQCAQzkNEkUAgEAiE8xBRJBAIBALhPEQU\nCQQCgUA4DxFFAoFAIBDOQ0SRQCAQCITzEFEkEAgEAuE8RBQJBAKBQDgPEUUCgUAgEM5DRJFAIBAI\nhPMQUSQQCAQC4TyWcp8AgWAkLMuCpmlQFAWTyQSKkjWMm0AgVAlEFAlVASeGmUwGyWQSLMsCAEwm\nE0wmEywWC8xmM/8zEUsCoTqhuIuDTBS9mEAoN5wYTk5OoqmpCRRFIZ1OQ/h3z7Iscr8HJpMJZrOZ\n/4+IJYGw5JH15SWRImFZIowMWZbF4OAgmpubs17DCVyu0HECmclkkE6nMT09DYqi0NTURMSSQFjm\nEFEkLCtYlkUmkwFN02BZll87VEKuWGYyGV78uJ/T6XTWNkQsCYTlARFFwrKAE8NMJgMAqsRQCoqi\neIHlfs49NkDEkkBYDhBRJCxpxMSwmOBwIicXiqLAMEzB54X/F54bsCiWqVQq63kilgRCZUJEkbAk\nUSOGWo+nFKFYCqNWrrAnnU7niWUwGERTUxMRSwKhTBBRJCwpGIbhC2gAdWKoVOD0FiSpc+YKgurq\n6kQjS4vFwkeYRCwJhNJARJGwJKBpGqlUiv9ZjRim02kMDw9jYmICJpMJNTU1cLlccLvdcLlccLlc\nMJvNedspTbeqhXtPuefARZapVCprbRNAXgrWbDaXPGomEJYzRBQJFQ3DMHya9OWXX8a+ffsUX/BT\nqRQSiQSOHDmCtWvXYs+ePXz6MhqNIhqNYnx8HLFYDDRNw2azZQklwzCGiKIUhSJLLnIuJJacYBKx\nJBCKQ0SRUJFwYkjTNADwa3JKLuqpVApDQ0OYnp6GyWTCvn37YDKZkE6nwTAMbDYbbDYbGhsb+W1Y\nlkUymeTFcm5uDsFgEDRNIxQK8ULpcrngdDp1q3BVAxFLAkF/iCgSKgZhAQpX7anmgp1MJuH3+zE3\nN4f29nZ0d3fj8OHDsvZDURTsdjvsdjtWrFgBAJiamkI0GkVLSwsikQii0ShmZmYQi8UAAA6HgxdK\nt9sNh8NRVpGRI5YAcPr0afT19QEgYkkgcBBRJJQdvcQwkUjA7/djfn4eHR0d2Lhxo2S7hBK4bR0O\nBxwOB1auXMk/xzAM4vE4H1lOTU0hHo8DAJxOZ9aapd1uryixjMfjMJvNeWIphBNJrsiHiCVhuUNE\nkVA2uItxJpPRJIbxeBx+vx/BYBDr169Hb29v3j5yG/DVnKsYJpOJjxKFMAyDWCyGaDSKUCiEyclJ\nxONxmEwmOJ3OrDVLm81WUWLJIRTL3CInrqiHiCVhuUFEkWA4uWLIXUyVXlBjsRj8fj9CoRA6OzvR\n19cnuQ+uAV9NG4OaC73JZILb7Ybb7c56nKZpXiwXFhYwNjaGZDIJs9kMl8uFVCqFubk5uFwu1NTU\nELEkEAyGiCLBMPQUQ5/Ph0gkgs7OTvT39+vuYqPXtrmYzWZ4PB54PJ6sxzOZDGKxGObm5jA7O4uR\nkRGkUilYLJas4h632w2r1arLuahFjVjGYjHU1tbCarUSsSRUNEQUCSWHm1gxNzeHRCKB5uZmVRdE\nmqbx2muvIR6Po7OzE5s2bZK9j0oRRSksFgsvGj09Pfzj6XQasVgMkUgE09PTGBoaQjqdhtVqzRJK\nl8sFi6W8X+dCYnn27Fls2rQpyxuW68nMde8pZ0UvgUBEkVAycsc3JRIJhEIhrFq1StF+IpEIvF4v\nEokE+vv70djYqFhQTSZT3gzFpRClWK1W1NXVoa6uLuvxVCrFF/ecO3cO0WgUmUyGNyQQiqWYIYGR\ncL9nTvyAt9Zohe5EwtdLmRIQCKWGiCJBd3LFkFtrMplMBY21cwmHw/B6vUin0+jq6kI0GlUliEDl\nR4pKqampQU1NDRoaGvjHONcbOYYETqfT0PNlWTYrAixmol5ILIXrlUQsCXpDRJGgG1JiyCFXFIPB\nILxeLxiGQVdXF3/h11JBWmzSRbFtK00UxaAoSrYhAVfsc/LkSUMMCbg1ZDnvQfh/4XsA8sWSE1tO\nLIkvLEErRBQJmpE72Dc3hZnLwsICvF4vAKCrqwv19fV523MVpEpZbpGiEsQMCViWxdGjR9Hd3V3U\nkMDlcsHhcGgWSz16RYuJJXcDEAwG0dLSQsSSoBgiigTVKB3sKxUpzs/Pw+v1wmQyobu7O2/9TLh9\ntQqb3nAR1nIwJBD+HwCi0SjC4TBaW1vzMhcAmWVJKAwRRYJi1M4yzBXFubk5eL1eWCwWbNiwAbW1\ntQW31ysFqqZPsZoEdakbEgj7UaUiy0wmk1UJCxCxJCxCRJEgG86KjbMDU9pWYTKZQNM0Zmdn4fV6\nYbPZ0Nvbm9ezV2h7teJEosxs1KzNqjEk4MQyk8kgmUwaYkhQKMVeLA1LxJJARJFQFGFk+NJLL+Gi\niy5SfEFgWRYLCwuYm5uD2WxGf39/3sW1GOUsllluoqgnxQwJIpEIMpkMTp8+LWpIwLn36IWadWci\nlgQOIooESaSm3Cv50rMsi+npafh8PjgcDrjdbmzdulXV+Sht6RCiVVCXG0b0aXKGBLW1tRgfH8e2\nbdsAlN6QQG6lqxzkiOX4+DgymQxWr14NgIjlUoeIIiGP3FmGatxnWJbF1NQUfD4famtrsXXrVlit\nVhw7dkz1eZWrgnQ5pk/LSakNCdRWKCtBKJbc8biJI8Ci8KdSqazvDRHLpQERRQKPXmIYCATg9/tR\nV1eHbdu2weFwAFhce1IbrQHaI0WSPn2LSnT00cOQgBMmI63iGIbhI1qhe48Q4Xg0IpaVDRHFKkfN\nLEOxCyrLspicnMTQ0BAaGhqwfft22O32rNdoETVu+3JFioTyoNSQgPv7stlsfDq2VIYEHJxAF3sf\nUr6whcRS2GPJufeQv8fSQkSxSlE72JcTJu51DMNgcnISw8PDaGxsxM6dOyUvEFq/zFrWBYWCylVK\nejweWRMnlmP6tBIjRSWIGRIAi+/L5/PxvZalNiQAtKVri4llKpUS/axomobb7SZiWQKIKFYZWqfc\nc20VADAxMYHh4WE0NTVh165dulYQSh1bS7QXj8dx8uRJRKNRuFwuDA0NIZPJwGq18q0G3AVTmP5a\njqIILM8ImPNH9Xg8aG5u5h+XY0jArVkqNSSgaVp30/VCYhkKhTAxMYGenp6s1whTsFx0ScRSOUQU\nqwRu1t3MzAxqa2tVVZICi8I0OjqKyclJNDc3Y/fu3SUXQw61kWIsFsPU1BRomkZvby8aGxuRTqf5\nu/tUKsVbnY2PjyMajYJhGD6yqKmp4WdAGrFWZUQUZ6TIG31DIfY5yTEkCIfDOHfunGJDAqP+LoC3\nvgMWiyWrMlc4yzL374eIpTKIKC5zcgf7vvHGG9i3b5/iLwRN0xgbG8PCwgJcLhcuvPBCw4fdKo0U\n4/E4fD4fwuEw3G43mpqasHLlyjxhrampQWNjY96aFRdZBINBxGIxvPLKKwCQVwlZTvcWLRh1zkan\napW0ZGgxJOD+DjKZjKHjucQi00KRJSeWuXAiKZw6QsSSiOKyRWxihZo/dpqmMTo6ivHxcbS0tGDF\nihVYu3ZtWaa/y40UE4kEvF4vQqEQurq60N/fj6GhIcXHcjqdcDqdqKurQyQSwbZt28AwDJ+Cm5+f\nz7pYchdK7v/l+B3JxehI0cgLrR7Vp3IMCWZnZzEyMoJQKIRYLIba2tqSGRIIUZKulSOWqVQq67lq\nF0siissMueObin2pMpkMRkdHMTExgdWrV2PPnj2wWCw4deqU6F2nERSrXk0kEvD5fAgGg+js7ER/\nf39WP5kelasmk0nyYsmlYAOBAN9jZ7PZsiJLrm2g3BgpVOWIFEuVzhQaEnCcOHEC3d3d/N9AKQwJ\nhOixhqlULOfn51FfXw+bzbbsxZKI4jKhmBhymM3mgl+qTCaDkZERTE5Ooq2tDXv37s16rda2Ci1I\nCVsikYDf78fCwgLWr1+Pvr6+vC9qqc/bYrGgvr4+a9wVVz3IieXo6CjfNpA7bcLhcCy7iwvHchJF\nqeNxBgNqDQmcTqdssaRpWrOwSiElcuPj43C5XKAoihfL0dFRPPzww/jOd75TknMpF0QUlzhyxZDD\nbDaLikM6ncbw8DACgQDWrFmTJ4YcWsVF6ACilNxjJ5NJ+Hw+zM/Po7OzE729vZIX33I42gh77HLb\nBuLxOCKRSF5xRzwex8jICDweD5+CK4WgGClU5RApI49X6CZTjSGB8GZJLLOQyWTyeoBLDSfkwnNZ\nWFjgK3iXE0QUlyhyB/vmImypABbvZIeHhzE1NYW1a9di3759RUVVS/pUy6BgbttkMgm/34+5uTms\nX7++oBhy5K5HKhEEvVsyhOuVwrYBmqZx9OhRWK1Wfr2KM9DOXa8sVaRQCpZ7pKj0/akxJBD2WMbj\ncdmTZfRC7HcaDAaLjntbiiydbxYBgPLBvrlwopZKpTA0NITp6Wm0t7cXFUMOPVxp1G5P0zQCgQDG\nxsbQ0dGBjRs3yr4YLQWbN664obW1Net9pdNpPgU7OTmJaDSaZ3PGpeDk/i2QNUV90eP9FTIkSCQS\niEajiEQiCAaDCIVC8Pv9JTMkkDo/IaFQKGu5YLlARHGJwN1FzszMYMWKFZoWuP1+P6LRKNrb29Hd\n3a3oS1QOUUylUvD7/Th37hzq6uqwa9cuVaOBlorNW66IWK1WNDQ05KXgkskkL5azs7NZzi1CsVTa\njK43ldySsRSgKAoOhwMOhwNNTU2IxWJYt24dnE5nyQwJ5BAMBvPWUJcDRBQrHGFkmE6nMTQ0hJUr\nVyreD1eMMj09jba2NmzdulXVl0Sv9KkchNFsR0cHNmzYgFgspst6pBIq0dFGGFU0NTXxj3POLdx6\n5eTkJBKJBN+8zomlkVWDS7Elo5Lh1jBLaUggROpvPxgMZv3tLReIKFYoYmlSq9XK/yyXeDwOv9+P\nYDCIjo4OmM1m1NfXq75I5a5JKkVOryEn/lNTU1mp3ampKV2EbTlFEblIXShpmubTb7Ozs7whwbFj\nx/LWK/VuGVnuhTZGU6z6VA9DAmGBl1QhUTgcRldXl75vrgIgolhhSA325f4tN2KJxWLw+/0IhULo\n7Ozk2xTi8bjmSC93ArnS7aXeg1AM161bl7fOWY4KUm7bpY7ZbM7qrwuHwxgbG0NXV5eoxZ3dbs8S\nSy1rVeWIFI2Mgo1GrYOOEkMCrsCLE0iuYlZoSBAMBsmaIqF06DHLEFgUQ5/Ph0gkktfADmhPf5Yi\nfZrJZDA0NIRAICAqhoW2lUslpkCNYuczDKaTuY+6AGwEzgBA/fn/sllhZfCzTWOYnp7OWqsSiqXc\n9JvRNxbLtd0E0P/3KWZIACzepMZiMczOziKVSuH1119HOp3Ga6+9hiNHjmBhYQHDw8Oq1hZHR0ex\nf/9+BAIBUBSF2267DXfeeSe+/OUv43vf+x6/RHT//ffjPe95j27vVQ5EFMuMXmIYjUbh9XoRj8fR\n2dmJTZs2ie7HyDXBYttnMhkMDw/j3LlzstpByjVPcamTL4jymE2b0NHRwf/MrVVxFZDj4+N8+k2Y\nfnW73VkWd0t9TFUhSjEhQw5G/D6tVisvdul0Ghs3bgQAdHZ2oq2tDQ8//DD+8Ic/4Mc//jGCwSCu\nvvpqfOUrX5G1b4vFggceeAA7duxAOBzGzp07cfnllwMA7rrrLtxzzz2leVNyzq1sR65yGIZRPb5J\nSCQSgdfrRTKZRFdXFxobGwvux2w2a0p/6iGq6XQaPp8Pk5OTWLNmjex2ELVTMrhtq1UU9UJqrSqT\nyfDrldPT0/D7/VmuLRRFIZ1OGyYgRn7Oy339Elj8fIVrmE1NTbjyyivxz//8z3jwwQfR3NzMG1LI\npbW1Fa2trQAAj8eDvr4+jI+P637uaiCiaCBaZxkK98OJYTqd5sVQDuWMFDOZDEKhEAKBANrb2yVd\ncwodW+0Fr5z2dMsdi8WCurq6rBSa0LVlamoKkUgEx44dy2pE5wR2KVvclStSNJJcUeQIhUL8Z84Z\nUqhhaGgIx44dw549e/DCCy/g4YcfxqOPPopdu3bhgQceyGpFMgIiigbAieHU1BTvRqI2MmRZFq++\n+ipYlkVXV5fiPxit1aNSNnGFoGkaIyMjmJiYgM1mw4YNG/i7RCWQSFE/mNkxxL77STDBaYCiYLvs\nZtj+7Hbd9i90beG8QTs7O7NGckUiEQQCAdF2AbfbrdribjkbBZTjxk5KFLlsgBYikQiuu+46PPjg\ng6itrcXtt9+OL37xi6AoCl/84hfxmc98Bj/4wQ80HUMpRBRLSO4sw9HRUbS3t6tqeF1YWIDX60Ui\nkUBPT0+WPZgS9IgU5W4vHDu1evVq7N27F8PDw5qOTURRJ8wW2G/8Kiwd28DGwwjfexksm98Bc1uv\n7ocSrikKLe6E/bZcu0AkEsH8/DxGR0ezKiCFYllJFndyJs4s5eMB4l6renyX0uk0rrvuOtx00024\n9tprAQCrVq3in//4xz+O9773vZqPo5TK+etaRuSKIRcVWiwWxRf1+fl5eL1emEwmdHd3w+fz5a3p\nKMGI9KlQDFtbW/mxU3K3l6JcLRlGYlSUY6pvgam+ZfGYDg9MqzeAmZ8suShKIdUukE6ns6JKr9cr\napztcrk0pdfVQtO0oZGiVNRWrmOq/XtlWRa33HIL+vr6cPfdd/OPT05O8lmkn/3sZ9i8ebOq/WuB\niKKOSA325f5wLBaL7Ob7ubk5eL1eWCwWbNiwgS+XtlgsZW2pKJQ+5aLhsbGxPDHk0CKK1RIpGn5h\nnx4GPXwSlq6dJdm/lupTq9UqOpKLM86ORCKYm5tDNBoFy7JwOBxIpVKYnp42ZCSX0WuK5VjDFBPF\nRCKhaVLHCy+8gB//+MfYsmULtm3bBmCx/eKxxx7D8ePHQVEUOjo6yjKWioiiDhQTQ45iosiyLC+G\nNpsNvb29eXfOZrNZsauNED1aKnJFlWEYjI2NYXR0FC0tLaJiWGh7JcfWWmiTSCTg9XoxOzsLq9XK\nF3tUYmrOCNhEBLGH9sNx0/2gHKWZeKD3upuUcTbDMIhEInjjjTfy7M1yU7Ba18KEx6yUMVVGHnNh\nYUGT7+nFF18s+l02uidRjOq6AuiMmlmGYoLAsixmZmbg8/ngcDjQ398vmSKtpOZ7hmEwPj6OkZER\nrFq1ChdeeGFWf5rU9mpbQrQU2qTTaYRCIbz66qvo7OxEV1cXGIYRTc1xbi7CmXbLETaTRvTb+2Hd\n9yHU7L66dMcxqE/RZDLxYtnZ2ck/nmtxNzw8jHQ6zY/kEqZgld4UVWukKKw8XW4QUVSBUjHksFgs\nWYLAsiymp6fh8/ngcrmwefPmPM/KXCpFFEdHRzEyMoLm5mZZYpi7vdpjK40U0+k0/H4/pqamYLFY\nsG/fPgDgizjEWgmEY3qmpqYQi8UQi8Vw+vTpkkQb5YBlWcQO3QHT6g2wX3lHyY9VToeZXIs7Dq5l\nJBKJZI3kstvteYN+pb7f1RApionicp2lCBBRVIRaMeSwWCyIx+N8e4bP54PH48HWrVtlRyPl7DNk\nGAYTExOIRqNIJBKKxFCP4yuJFIVuOevWrcOOHTtw+vTpomuLuWN6OI4cOYI1a9bkRRs1NTV5htpL\noZmbPnsY6Rf+A6a1/Qh94WIAgOND98J6wRW6H6tUUytcv7kHpmQo6zEPgJUAUKDImbHVInrF/0ZN\nTQ1qamryRnIJb4pmZmb4kVzcOCbuc7bb7WAYRvF3QAvlKLQRE+Ll6nsKEFGUBcuyiMViYFkWZrNZ\nsRhymEwmhEIhHD58GHV1ddi2bRscDoeifSgp1hFDzR07wzCYnJzkx1a5XC709PSoOn6pi2W4ytex\nsbEs67hkMqmpgIWiqLzqSGGDeiQSwejoKKLRKIDsC6hcj1AjsWzch/pHFww5VqkixVxB1GM7qZsi\n4TimYDCIiYkJJBIJpNNpOJ1OpFIpXixLmUGoFFu55TpgGCCiWBDh+Cafz4f6+npV/YEsy2JychJe\nrxcURWHXrl2qK7fMZjOSSZVmlgphWRYTExMYHh7GihUrsHv3btTU1GBmZkb1PrWKohTCYp/W1lbs\n3bs36466FOX6wgZ1oaNQ7gWU8wjl1rCEYrnc3VCA5eF9KrS4E/bSnT17Fg6HA2azGdPT0xgaGkI6\nneaLuPQeyUXTdEWk7ZfrgGGAiKIoes0y5CKs4eFhNDY2YtOmTRgdHdVUyqw1fSoHTsSHhoawYsUK\n7Nq1S7cvot52a5xwDw0NFVzfzE29lvIiLXUBTafT/Jgm4RqW0PaMpukl0zoil+XuD+rxePKiplQq\nJTqSS/hZcy0jSn43RkeKUn+LoVAI7e3thp2HkRBRFCAmhmp6DLm1t+HhYTQ1NfGionWWIVBaUWRZ\nFufOnYPf70djYyN27twJm82m6zH0EkWWZREIBODz+bKiWCkqoU/RarWioaEhbw1LaHuWSCTw6quv\nZgmr2OSJpcRyiBSlkBKpmpoaNDY2ZmUQcj/rqakp3kSbq37lPm+pdLvRoih1Q0PWFJc5hQb7cnBF\nMsX2w7UoNDc3512ota4HcvvQQxSFFyqhwDQ0NBQVQy7qUruuqkUUuSIlr9eLuro67NixQ1bkrYco\nluLinmt7Njc3xzczi02esNlsWUJZqDKyUjBSFM9MhHDDQy/yP/umIvjKB7fg01duLMnxlHwPpCzu\nuNagaDSK+fl5jI2N8SO5clOwRouiHDPw5UZVi6IcMeQoJGg0TWNsbAxjY2MF+/X0iPK0Nu9z++C+\nzIFAAH6/H/X19bIFhhM2o0VxdnYWsVgMU1NTiouUckWxUqMX7pzE2gi4wp5IJMJXwXKVkWLN6ZXy\n/oz8XW9cXYvjX383AIBmGLTd8XN8YNeakh1PDy9Sk8kkanEnHMkVCAT4f0ciEdTV1WXdGJVKKKVE\nkawpLjPUDPYVE0Whx2cxJxdAn2IPPYSVoiicO3cOIyMjqKurw/bt2xWtc6qZlMGhRhTn5+cxODiI\nmpoa2O12VX6IWi/KnKiWU2iEhT25Ti5iZtpcsUejpQNzGeUXzZU6Zc7L9Xv7/akAuprdaF9ZuPdX\nC6X0PhXroz1x4gTWr1/Pe8KOjo4iFovx65XCGyM9LO4KRYpGj3QyiqoSRS1T7oWFNplMhhfDtra2\nomKoJ1pEkTMLCIVCsNvtqlpCAO1WbXJFMRQKYWBgABRF8ZZ3L774YvENZaLkYm3kmqTS40gN/+Xa\nRZ6yn+OLPhiGgdPpBMuysFgs6OjogN1uL6lolUsUf3J4BDdetK6kxyjHGp/D4UBtbW3WjRG3Xsl9\nznqN5CokimRNcYnDmQgD6gb7WiwWJJNJfmJ8W1sb9u3bZ3hJvRpRFDrneDweNDY2orOzU5UgAqU3\n9Y5EIhgYGABN0+jp6dE9TcN9/uUuvCk1Us3p8XgcY2NjiEajGBgYQCKRyFu/0tMHthzVp6kMjZ+/\nMo6v33BBSY9TKY42wvXK3NdLjeTKXa+UmpkodrxoNKppWk8lUzWiKGXSLYd0Oo2RkREsLCygublZ\n8cT4XLTcOSsRRc5T1ev1wu128845p06dKptVXCFRjMViGBwcRCKRQHd3d1blnpByRB7LRUS5i6fH\n44HD4cDatWsB5K9fCX1ghUKptIUAKM/n9czxSezoaMCqOvXtT3Ix8r0pdQcqNJKLiyrPnVvMJHAj\nuYRiKRYpckPTK73ASy1VI4qA8jW9VCqF4eFhTE1NYe3atXA6nZp7czhBUXsXLucLyLIsZmdn4fV6\n4XQ682zk9JiUoacrDTe5IhwOo7u7GytWrJB8n+Va21suoiiFHB/Y6elpxONxUBQle+qE6zf3YHcy\nBAwoPyfOjk0Nj700ghsvWp59dHog1R6UTCZ5sZydncXCwgIoisLCwgLcbjeGhob43lu138HR0VHs\n378fgUAAFEXhtttuw5133om5uTnccMMNGBoaQkdHBx5//PGyrFtWlSjKJZVKYWhoCNPT02hvb+et\nwsbGxjTvmyvYKcUapFAMHQ6HpMF4Of1ThV8kLh09Pz+Prq4u9Pf3889/5FMmLATFvnQXA/9c+Bj1\ndSx+9JB+BgHLETk3FlKWZ8KUXFEfWJVWbIB6G7doIoPfnjqH79yyS/WxqxHhSC7u8+aWXJxOJyKR\nCI4cOYLnnnsOo6OjuOiii9Df348tW7bguuuuw5o18qp8LRYLHnjgAezYsQPhcBg7d+7E5Zdfjh/9\n6Ed417vehQMHDuDgwYM4ePAgvvGNb5TyLYufn+FHLCPF7vaTyST8fj/m5ubQ3t6O7u5u3VMEpWq+\n58SQq84sNG2j3JM2WJbF2bNnMTMzg46ODvT29uZdoMUFUR5atpViuUWKWt6LVEpO2C7CVUW+Q+uJ\nqsBlt2D2O9cWfI3nqdsU71dL5CqHL9rfQJgq0m51iQ3/hteyHvKwFvxdor8k55TJZGC1Wnlzgc9+\n9rO47bbbcNNNN+GZZ57BG2+8gZMnTyKVSsneZ2trK1pbWxfP3eNBX18fxsfH8eSTT+LZZ58FANx8\n88247LLLiCiWi0QiAb/fj/n5eXR0dGDjxo2Sd9FaU3d6NPALz2Nubg6Dg4Ow2WwF5zAKKVekyE2u\niEajaG9vx969e0u2LvH+/WLrJ42ZAAAgAElEQVRrvm8H/oX7d36RUV0ti+99MyG6v+UmioD89JfY\nNAopVhR/yZLFlAzxYloKgSwqiDpvJ4dCY6NcLhd2796N3bt3q97/0NAQjh07hj179iAQCPBi2dLS\ngkAgoOnc1VLVohiPx+H3+xEMBiUjFiGcGGgpstGj+d5kMmFubg4+nw9Wq1W2GArPwchIkaZpjIyM\nYHx8HGvXroXL5ZKdajGSYEj6sy+FKO58hsF0nrf7NmAEAKRvOlbagFeu1HYzoeTmTksKVAwlrjPl\n7g2VwpQMgWGYijw3PRGrPg2FQrrMUoxEIrjuuuvw4IMP5u1PbVGkHlSVKHK/5FgsBr/fj1AohM7O\nTvT19cn6ALheRS2iqNWmbX5+HtFoFMPDw3zvnlK09Bly28uJFIWTK1avXs23sIyPj6s67skjt2J6\n8peosTXj4ncfV7WPSiJfEEu7XS7luugocZ05evQoTCZTVgXsmiNfhSkVNvKURdHDzabSEYsUFxYW\nNPcoptNpXHfddbjppptw7bWLqe5Vq1ZhcnISra2tmJycVDWRSA+qShRjsRgGBgYQiUTQ2dmZVdgh\nB7PZjHQ6rckkW236dGFhAYODg/x6Tl9fn+o+Q7PZrGgNIJdioig0RF+1apVu5gZt62/Gup7/iZMv\nf0zzvpSyFNKnStKcfdw/Xin9WlkhirnOXHjhhaBpOqsCdl0FCCJQWjcbIQxN4+d7boWrbSUuf/Lv\nS348IWKV8lp9T1mWxS233IK+vj7cfffd/ONXX301HnnkERw4cACPPPIIrrnmGtXH0EJViWI8Hseq\nVauwadMmVXfJVqvVcO/SYDCIwcFBUBSFDRs2oLa2FidOnChroYzUTEfhlI1ikyvUpMUaV74dseiQ\nmlPWzFIQxVIM3S01clxn8nxgz5TufJSkdo1ys3nj2/8X9X3tSIdiJT+WGLnfU60TMl544QX8+Mc/\nxpYtW3jz+/vvvx8HDhzA9ddfj0OHDqG9vR2PP/64pvNWS1WJYlNTk6b1PIvFgnQ6rekcOGecYgjF\nsLu7O+vOTGsKVu9CG84xx+v1or6+XtaUDSPXipSkXY8cOQK73Q632w2PxwO32837whohiszsGGLf\n/SSY4DRAUbBddjNsf3Z7yY+rFD2mURjlOqMEJaldI9xsomNTGH3mJVzw+f14/cH/KOmx5KI1Urz4\n4oslv0u///3vVe9XL6pKFLVehPUa/RSNRiWfD4VCGBwcBMuyeWLIobVYR4uhN5AtirOzsxgcHITL\n5ZLtpaplyoYalKRdd+/ejUQigUgkgnA4jMnJSSQSCf5GpqGhgV/bKkmUYLbAfuNXYenYBjYeRvje\ny2DZ/A6Y23r1P5YG9JhGoafrTClGRhVL7RqxpvjyZ76N3V+/HemI8VGilHAFg0GsW1daT9lyUlWi\nqBU9RFFK0DgxZBgG3d3dBdMT5e4zNJvNiEajOHr0KGpqaor2Reai16BhuShJuwob1oUz706dOoUV\nK1aApmlMTk4iEonw5tq7Rg/BmpG+0ZFi3gwE2Fr0Mm+tE5nqW2Cqb1k8F4cHptUbwMxPVpwoClE7\njUJP15lSjIwqltot9ZriyC9egH1lPZp29mLyuVdLdhwppG5cl/MsRYCIoiL0Sp8KBSkcDmNwcBA0\nTaOrq0uWrZEe6U+12weDQQwMDCCZTGLHjh2qq1+NFEU94Ayzhe+XZVnEYjFY/coFkWMVJb2eR08P\ngx4+CUvXTtX7N2LorpppFKV0ndFjZJSc1G6p1xSnXjyJkadfwNivDoNOpJAKRfHc/q/g0kfvLdkx\nhVTjgGGgykRRj/RpPB7XvI9MJoNwOAyv14t0Oo3u7m5FHn/lWFMUTq5Yt24d5ubmVAkioF4Uj7/0\nYcxPP4dUcgZ/fKoDPZvuxZpO4ytROTgP0FLAJiKIPbQfjpvuB+VQ3xNW6qG7atcF5bjOqEWPkVFy\nUrtnz57l/WG5lHohH1il7PraJ7Hra58EAEw+9ypOffMnhgkiID0hYzmPjQKqTBS1okf6NJFIYH5+\nHm+++Sa6urokJ0EUgmsNUYsSURSbXHHzX1EIhteqOnZ9HYu7blUnitv2/auqY+qBofMUM2lEv70f\n1n0fQs3uq3XbbymG7pZ6GsWnHa/lPXaowOv1Kt6Rk9pdv349UqkUGhsb5fnALrGpElKDC4goLiPK\nWWgTjUZ5cbFarZqskcxmMxIJcTsyudsXE8V4PA6v14tIJJI3uSIYVv/lXghSSzJ9apQosiyL2KE7\nYFq9AfYr79B136UYultp0yj0EGm5qV2GYWCxWGT5wHLFdU6nM8uIwGazyboutV66A62X7lD9ntQg\nlT7V2pJR6VSVKGqFc7RRQjQahdfrRTwe59Okhw8f1nQeWtcUC13guckVCwsL6OzsVN3TWQijRVGP\ntKvS34HatTz67GGkX/gPmNb2I/SFiwEAjg/dC+sFV2S9LhqNwul0yj6vUrQ/VOI0Cj1EWm5qlxNF\nMWpqatDY2JiVCWIYBvF4HJFIBMFgEOPj40gmk/zAX1ROZwoAaVFMpVJ8m9JypOpEUcsdv5JCm1gs\nBq/Xi1gshq6uroIzApWihyjmkk6n4ff7MTMzg/Xr16O3txcf/WtzSSZOGC2KStKu198q1VKyeMUq\nZBouRO1anmXjPtQ/ulD0dX6/H7FYjLdA83g8b7nUiFCKNGcp1wU5Dj3+sKLX/+P+HbBbjUlTckN5\n5cJ9Vi6Xi59JCCx+9xYjyZESnKV6pAYML3eqThS1ICd9KhTDzs5ONDU16R5paS20EZLJZDA0NIRA\nIJA3uUKJICppkF+K6VOOQqbhUpRiLW/z5s0AwFughcOFrc8qLc1ZKkq1timGXn2KVqv1fDqy8kTR\narXmPV5Os24jqDpR1BIpmkwmyW2Fa3BdXV0lEUMOPSZtsCwLv9+PiYkJrFmzhh+krBYlDfJLWRTV\nUIq1PI4sCzSJVrZKTHNKcdf7PoqQQ93NQ208im899UOdz0gao7xP5XDixImstUqn06n53DKZTJ4Z\nRyqVEhXK5UTViaLexONx+Hw+hMNhRWtwWhxdtKRPuckV3ML/3r17dbnbVdIgL0cU6zyMpoKeSqES\nrMzkpDn9fj9vaye3+EMuf2j5eMHCMrEKUzWoFVO1VNKUjN7eXr6wZ3Z2FrHYogOO0+nMaxeR+9mK\nVZ9ysxSXM1Uninp92ROJBHw+H4LBILq6uhRN3ODSn0aKYu7kCpfLhY6ODsW/j5NHbsWWC7+vaJtc\nColiPB7H4OAg/urmOHp6evL6NznbtfXr14tuLz5cuHyUumVBL1wul2jxh9vthn5t/ssLvSNFD2tR\nNTDYw1pgs9lgs9mwYsVbY54ZhkEsFkMkEsH8/DxGR0f5SC+3XURM3MXWFJd74z5QhaKoFYZh8MYb\nbyAYDCqaxSiEW5tUm4ZQIopSkytmZ2cl+5AK0bb+ZjWnnMVdX+rO+rm+jsV3H0jA6/ViYWEB3d3d\nkulniqI0p16lhL0U8xqXylpec3Nz1vy6dDrNRx4psxM1tErvzYU43nnTu/IeZpqbER0cVHu6ZYex\n1eru3/t3if6Czx89elRRK5fJZOJvbIQIP9vx8XFEo1HeslCYgk2n06KRIhFFAoDFyNDv9yMej6Ou\nrk6VGHJoXRMstLbJUWxyBSesSkWxceXbVZ1zIRaCFI4ePcpXvRb6vRZLvdbXsUULhKSEXe95jaVa\ny1upfpynbKxWKxoaGtDQ0IDk2geRBOB56rb8F970E1X7N01NaTtBnQi/77uqt6VPnKiY9KkShJ8t\nB8uyfLsIZ4Q/Pz+P119/HR6PB06nE2fOnOGvf2r52Mc+hqeffhrNzc04deoUAODLX/4yvve97/Fe\nw/fffz/e8573aHuTGqg6UVQqZFzf3vz8PNavX494PI7GxkZNaVg9q0dzYVmWn1zhdrslJ1dobevQ\nG7mFPsUKpX70ULZgiqVTpYRd7rpobtvGMxKzUOW2LIy8/633ffz4cfT39+tmFbacKOewXdHzqaA1\nRa1QFAWn0wmn08lnDI4ePYqtW7ciHo9jZmYG//7v/47XX38d8/Pz8Pl82LJlCy644AJ86EMfkn09\n/MhHPoI77rgD+/fvz3r8rrvuwj333KP7+1JD1YmiXJLJJPx+P+bm5rIimOnpaV3GR2ndhxjz8/MY\nGBiA3W7Hli1bCvpyah0flYvWBnm5aahqq1xVAmOrVTUwmLGJF064urtLGtFxBgRyKfew3VyMrD5l\nGKYsbRA1NTWoqalBXV0dfvCDH+CRRx5BKpXCBz/4Qbz22mvw+XyKzuuSSy7B0NBQ6U5YB6pOFIt9\ngKlUCn6/H7Ozs+jo6MDGjRuztlHjapOLHi0VQriBxCaTCX19fbKMurVMyhDDKF9SOaljjo98aulV\nr2q58EWv+N+yX3vmzBm0tLQUTIWVOsXZ8oe7Fv9xfXE7u0octmvkoOxST+QQQ+x7FgwG0dbWhnXr\n1uk6U/Hhhx/Go48+il27duGBBx5QNCBBb5beVaNEpFIpnDlzBkePHoXb7cbevXuxevXqvD/6UoyP\nUgNFUQiHwzh27BgGBwfR3d2N7du3y55cUWnpU7koKbQphRsPoTj/CGAzgE0AHtRpn9ywXcpUWZ+p\nUaIoZblmNKFQSPeWjNtvvx1erxfHjx9Ha2srPvOZz+i6f6VUvSimUimcPXsWR48ehcvlwr59+9DW\n1iaZFtEj9al1H9FoFPF4HG+88QY6Ojqwc+dOxYvfakXx+EsfVryNniiJFAnSlCrKOQXgewCOADgB\n4GkAWmtMhcN2qxWjI8VCA4b1NgNftWoVzGYzTCYTPv7xj+PIkSO67l8p5b/1MBjuQpBOpzE0NISp\nqSm0t7fLLvTQQxTNZjOSyaTi7YSuOQ6HA1u3bhUtopF7DmpEsZzjmwB9WjKkULMuevLIrTh3WRIt\ndQaUhBbA9Zt7FK0n7gaAgcX1RCVp13/EouixAD4O4NM5z58GsAcAt1J4KYCfAvhsgX1+88lDuPua\nWySfL/ew3UrAaFE0ckLG5OQkWltbAQA/+9nPeAvDclF1okjTNAYHBxEIBLBu3TrF9mZ6DRpWIkjC\nyRVdXV3YtGkTTpw4oUkclmrBitbz5noR33nNRN5zagS/bf3NuPZnLpx8+WMFexufueYvFe9bCWoK\nbKS2kyqwEUaBNQDejXxR3AzgfwGYBeAA8EsAxRpS6pKFv0+lGrYrVWBUiVSKKGqNFG+88UY8++yz\nmJmZwZo1a3Dffffh2WefxfHjx0FRFDo6OvCd73xHy6lrpupE0Ww2w+FwqPb6NDJ9Kiz6ye3h07ou\nuZTXFLWkT7leRL1QYm8nl3Knh6UKbMSiwFz6AHwOwBUAXAC2ATC6aeEWQeHOlybW8o3qwiZ1t9u9\naGuXTCqyPuMw+jMqhyiKHU9rpPjYY4/lPXbLLdJZgnJQdaJIURTWrFmjaXxUqatPcydX9PT05Am4\nVlEzm82aC4bKgdZIsRQiJofaW/5T1jzFSkYsCvyiyOtuOf8fAPwtAMmBWYLG/2/e/RvcPfbzoueg\nZNiuh7XkNakXsz7j/nO5XAVvmvV2symG0YU2UseLRCLE+5SQjV6Ropig0TSNkZERTExMYO3atQWj\nWTFh/cinTAoqLt8qp66vY/Oa3vUkFh3Cq//9fs3WaYvvzwXgQn1OzECcNouseYpycf3N+2C6sAmw\na59YkGfInX4eAHDIenHWw30A3jn6JD7bsuiv2Y+3xK8QAQB3nZvFt9ZKuBwAqAvM4dDjD2dFeWp5\nML5V8jkp67NUKsVHlCMjI7yhttD2jDPUBoyP3MpxPDFRZFl22RgWSEFEUSF69CnmCivDMBgdHcXY\n2BhWr14ta3KFWKSotgVhqbQuLJXzFEPveYqm0Bxgb9Vtf3JJt6wo/iIRQiq3M4qamho0NjaisbGR\nf4xhGESjUX7yxPDwMFKpFGw2GxwOBz8c2OFwlDxqpGna0JFN1TpgGKhSUdSyLqVHnyIX5eVOrtiz\nZ4/sFIkRa4JyfESLodXpplSkkjOosTUZdrxC8xSPHTvGj23KZDJofPZvYUoVHhpMECdoc+DunMjX\nw1qKmm2LYTKZ4PF4snp/WZZFKpXCzMwMgsEg/H4/YrEYTCZTXlSpp4hVQqENd81czgOGgSoVRS3o\nIUYURSGVSuHw4cNoamriJ1cooZT+qRw/eohBMBjE2bNnUVNTg56eHvzFJ+WZA3CUu4VDiiN//B9F\n07mPf/+tqshz587hr7+QP65KSvRf+R9RpAXTog7jD/ii1Mc1/NY/66h6DJmIIKpFrLVDzTgmKSiK\ngs1mQ21tLUKhEPr6+gAsihYXVU5PT8Pv9yOTycBut2cJpcPhUCUq5RBFuz173Fk0Gi1oHblcqEpR\n1HKno2VblmUxNTUFn88Hmqaxd+/erMkVSih1oUwkEsHAwAAYhsHGjRsrdnFd6bgnpZHrx++2Ixii\nAIjPb5QS/bTK8YlB1kAj8P/5BBBM4JCCSRe564yFCK5qlFU8I6Q2HjV8WLAackXKbDajtrY263vC\nsiwSiQS/VhkIBBCPx2E2m/mo0uPxwOVyFc0QVUKkWA0DhoEqFUWjEZtccezYMdWCCMj3T1UqGolE\nAoODg4hGo+jp6claYyl0DK2Dh9WidNyT0sh1URCXAOcFrpKoC8wp3uZbT/0Q4fd9F1+0v6FrhKc3\ncqpPKYqCw+GAw+HgxyIBi4ITjUb5EU3RaBQ0TcPhcGRFlXa7nb8JrxRR1LtxvxIhoqgSuTZZwskV\nW7duzZoKoMVqS24aV65opFIp+Hw+zM3Nobu7GytXrpR9bnoMHi5GNBoFkH+XWq4Wi4qjwgRRK5Us\niIA2kbJYLKirq8uyZhSbZ5hIJGCxWOB2uxGJRBCPx2G32w0RR7E+xVL4nlYiVSmKWheKuV65Qn+c\nwWAQAwMDMJvN6O/vzysB5+zKtHyx5IiiXNE4evSo6FQQOZRi8DBHMpmE1+tFKBQC8LaSHccImNkx\nnLlnO1po5WnvjLsGuxrfuqE6/ra1ep4aQSF69ymKzTMEFu0ouerXQCCAoaGhLAMCLgWrxoCgECRS\nJCiCa6kQE7RwOIzBwUEwDIOenh5Jo25O1NSKot7Vp2odfkqF0MCgq6trsaDh/5T7rBYpZBXHPed8\n70D+hmaLKkEEAEskhePnBxbTDAP88rSq/ZQbrplfP0+h8mBUOtNqtaKhoQEWiwX9/f38zXQ8Hkc4\nHMbCwgLGxsZUGRAUQqxPMRgMKh48sBSpSlHUekfFiaJwTTAajWJwcBCpVArd3d1F54Fx+1A7YV3v\nmYzlFMT6urfaYxiGwdjYGEZGRooaGChB6dpqIQpZxXHPiUmWqb5F03E5fn8qgCtUbFfMzLvU+xrB\nojn4YQ3HZWgaP99zK1xtK3H5k3+vYU/aMNrRBnjrusW1f+RWggoNCEZHR88vOQBOp5Nv+REaEBSC\nZdm891eKCRmVSFWKolaEzffc5IpoNIru7m6sWCGvSVmrqC1V71IAeOJRGi+++CIuuugi/jGuMtfr\n9WLlypXYu3evrrZWSgtyClEoJW3EGudPDo/gitXu4i8UIGbm/V4A3SqOr3Zf7wPwTwC0XFbf+Pb/\nRX1fO9KhmIa9aMfoZno5KDUgEKZf5RgQBINBtLToc2NXyRBRVIHVakU8Hsf4+DiCwSC6uroUFaYA\n1WvoDQDv328G8HbgX3KfWX3+v0Xk2M/JbbFYLgU5qQyNn78yDqxW5qGqZqST3vs6UeT5u973UTzw\nm/8n+Xx0bAqjz7yECz6/H68/+B+SrzNirFQ5IkU1FDIg4Ip6ZmZmEI/HQVEU3yqSyWSQTqezhD8U\nCpH06XJFS/o0lUphYWEB586dw4YNG9DX16dqf1o9VOUaYxvpKKNnihKQZ+tWqeYASlCSinzm+CR2\ndBROzYuhZqSTEfsSEnK4Cs52fPkz38bur9+OdKRwlGjEnEUjWyT0tlfjDAhsNltWZoszIAiHw6Bp\nGidPnuTX9l9++WVMTU0hHA6ruiH42Mc+hqeffhrNzc04deoUAGBubg433HADhoaG0NHRgccff7zo\nspMRVKUoqkFY+OF2u7F69Wp+MKYatKZP5QqxkaKhZ4pyOSJ2cVOainzspRHceFE7EFY207MPwPH3\n98LpWLzzf0nR1gDiaeCJN/l9GT0eauQXL8C+sh5NO3sx+dyrJT5acYyMFI06FmdA4HA4MDU1he3b\nt4NlWaxZswY0TeORRx7BD37wA3zjG9+A0+nERz/6Udx6662y9v2Rj3wEd9xxB/bv388/dvDgQbzr\nXe/CgQMHcPDgQRw8eBDf+MY3SvX2ZFP58X8JUBLZ0TQNv9+Pl19+GTU1Ndi3bx+ampo0py6NsGkz\nmsaVb4e1pnizf7VCn80vMRGmIi14KxUpRjSRwW9PncO1u89P2/jNm8DTry/+JwNOEFWRs+0tAF4B\n8F8AGgBsUL/nLOLxuOjNw9SLJzHy9At4vPuDePamL2Pij6/guf1f0emoyjEyUixn4z5FUVi9ejVu\nvPFGuFwu/PCHP8SxY8fw61//Gu95z3tk7/OSSy7JMwJ58skncfPNiz3ON998M5544gn93oQGqjZS\nLGYKXmhyhcViQTyu7E49Fz2MxTkymQz8fj+AXl32RygMl5J+x9Wjks85bngz7znLxn15jylJRbrs\nFsyeb8sAAKTKd1M1BaAZ+lSUCvl8o0grC4BdX/skdn3tkwCAyedexalv/sSQNKkURkaKleBmA2T3\nKYqN31JKIBDgs20tLS0IBAKa9qcXVSuKUggnV7S0tIhOrtBr0LBWYWVZFn6/n5+/SJBGz7XVQilp\n7rnDiMraVyVMqlfDdVgUciu0V5QuRaolUhSSTCbhcDhKckyKoipm+gYRxfOwLIvJyUkMDQ2hqakJ\nF154oWTJdSkHDcuBE+5YLMYbiy/XwZ+LlaraUbq26nFlsLCwgMX4rbTInlRfIr715gy+750DRQFb\n6uz44d41sJsLR0H/rfM5BFfJT7u3XroDrZfu0PkMlGF0pKhne1IxjBobtWrVKkxOTqK1tRWTk5NZ\nTj7lpGpFkUufCidX1NfXY+fOnUWNuvUSRaX7EPbyrVixAnV1dVi7di0viGrnHwqb56udn3w3ylfg\nBQJhAKUf5KsqFVlj1iV9Oh5L49tnZ/DGezbAYTHh+udH8JPhID7SqW8VYG08imsOfx/pSAynvvkT\nwxvv9RYxI6M3Kfcso4+nxatZjKuvvhqPPPIIDhw4gEceeQTXXHONbvvWQtWKIsuymJ6ehtfrhcfj\nwfbt2/Pmh0lhtVp1SZ8q2YdwysaOHTtgt9tx7NixrGizWE9fLq+//jra2toUuVQUEl6j2j8Ov7dw\nanLv0+pHD4n1dZUaVanIK3plF9gUI8MCcZqB1UQhRjNY7dDvsnDo8YcBANMpFgc+/KmyVY6+8sor\nWX14nMOL2gis2tYUtQrzjTfeiGeffRYzMzNYs2YN7rvvPhw4cADXX389Dh06hPb2djz++ONaT10X\nqlYUufFIuZMr5KBHkYzc9ClnLG6xWLB58+YsayetDfwmk0nx9pzwiqU1l0PPYDlQm4q869sHEapf\nbKY+9Jj8OYdC2pxW3NPbhHU/PwOHmcIVLW5c0arfDcEt19+BP/2vf8Hgv/0api8/BzqRQioUVd1g\n/81PfQ51wZDi7ZjaRoQOPsG7uwQCAXi93qyRTZxQ2mw2WRGRUWtg5RDF3GyZ1gkZjz32mOjjv//9\n71Xvs1RUrSj29PTIan4Xw2QyaW6oLZY+jUajGBgYQCaTkTQW18MVR+3vgABc9U9Pwl6f5H++72fv\nQiRRONvQ8OhC3mPNCwGc+eviDjXh930XAPBpx2sKz1Sa+RSNJ8dC8L9vI+przPjQ8yP4V/88Prxe\nv/SpnpWjagQRAEyhOclBwNzIpmAwiPHxcSSTSd5cmxNKp9NZNgcbo0VRygy8GnxPgSoWxXJXOkml\nTxOJBLxeLyKRSFEv1XL4p7Ise750uk31caXQ2xFHDdffKr+wRiiIAIoKohRT9atkvW7nMwxeuVLf\nC/PvzkWw3l2DlfbFS8G1a2vx4kxMF1FUUjxTLqRGNglt0GZnZxGLxfj0q8fjQSaTkazS1BujfVal\nxkZVg8UbQESxbOTedabTafh8PszOzqKrq4sfE1MIrelTpdvPzc3h7Nmz59fb9BdFvRxxUjUMalL6\nisePvj0Ln8+HzZs3849Ju2+Whumk9HPBVY2qJt2vc1pxeCaGWIaBw0zh9+ci2LVC/MbglvTzivef\nSyVUjspBzFxbaIOWyWRw4sQJ0DRd8tmGlbCmWC2+p0AVi6Ie6FGNRdM0hoeHMTk5ifb2dmzYsEH2\nPo0SxUgkgjNnzsBkMmHLli15I2v0Qi/T7levEO//tCaAnb9Td+7FzB6MIpFIiHaJ3D32c/7fYuOV\nDlnF1xz3NDnxwXV12PGrQVhMwPYGB27rEo/w9mFY9PEUTHgFi32yh/bfnvd8sK4Wdz+kzr5LbH9i\nqGkrUQqXfvV4PJiYmMDOnTv59Gs4HEYwGORnG9bU1GQJpdPpVH2tqARRJJFiFaDXTEW1aQ2GYZBK\npXD48GG0tbWp6jXUQxRTqZTk84lEgi9I2rBhQ0WY9QLAH7f4kUqlEI1G0dPTg6ampqKfpx79juUU\nxUDdYmrvzJkzwN7C7zV3vNIvfrYRDY8uYP6Zt4u+/r4tq3DfFnkpXDFqwPCC+f1HD8CxEMFNf/0w\n/7zadUC5GNVWwiG8GRamX1eteut3mEwm+dmGMzMziMViMJlMWeuUbrdb1nfeqDSt8Hi551UtsxSB\nKhZFragVRZZlce7cOfj9fjAMU9AkQM45FBK1YkhVn6bTafj9fszMzKCrqwubNm3KEx05PZGlWiOc\nnJxES0sL9u7da1jxg5qbKGZ2DLHvfhJMcBqgKNguuxm2PxOPfMQKcMR4n38L4F/8t82exlUfOJP1\nvNh4pWTC2Ll/8Xpt9vJ7uIIAACAASURBVF9qKGVbSS5yIjepKRScUE5OTiISiYBhGD79yrUC5Q4B\nNjpSZFk273gLCwsV01xfaqpWFPWKFOXCsixmZmYwODjImwQcP35c03noXWjDMAxGRkYwPj6OdevW\nFRSdHz3E4MSJE+jq6oLb7RaNxEo1NWPNmjWoq6vTLIhKRFtV+tRsgf3Gr8LSsQ1sPIzwvZfBsvkd\nMLfp41ErJnZyxystJ0rdVpKL2h5Fs9mMurq6rDQky7KIxWIIh8OYn5/H6Ogon37lIspUKlX22Y3h\ncBjd3WpGUi89qlYUtaJEFBcWFjAwMACbzYYLLriA74vkRE1takSvNUUuevX5fFi1apWo36vU9oVa\nOko12NdsNuuSylQi2mpE0VTfAlP94qRyyuFB7T+8ouo85VJp45WMwoi2EiF6Rm5cRatwnT53CHA0\nGsVrr70Gs9mctU7pcrkMiyCDwWDFLJ+UGiKKKpHjahOJRHD27FkAQG9vb55Lih59hlq3j0ajePnl\nl1FbW4tdu3YVtbgToqb5vxByHXHkDlguhlLRroRCm0Jw45XGfnU4q0keV+rnFHKg+07Y3XZQZhPM\nFjO+8PJXddu3WkrZViJGqd1scocAT09PY9euXVnVr+Pj44hGo2BZNiv96na789KvSpD6GyfVp1WA\nHulTKVebeDyOwcFBxONx9PT0SN5hafVQ1SKq4XAYb775JuLxOHbv3q2qolQvceKQ64hz15cW0zj1\ndaxiazu1lKuFJ/T5vQXXIoVINcn/VNxMRDWf+d0X4GkyzgavGEraSvSAYRjDDfgpioLFYslLvzIM\ng1gshkgkgrm5OQwPDyOdTsNms2UJpcPhkPU3LJW5CoVCJFKsBrSU2YsJWiqVgtfrxcLCArq7u4tW\nReqxJqh0+0QigYGBAcTjcbS3t2NyclJ1i4XWSFUraszP1VKulgzPvb/VbS0yUNOIVSnlvYwAEKsr\nTRuOHihpK9EDmqbLvsbHwVW0CmcbsizLV78uGtsHEI/H+fQrJ5Ri6Vcpj1PSkkEoinDQcCaTwdDQ\nEAKBANavX4/e3l5Zd2VGpk+F5gDd3d1YuXIlUqkUxsbGVB9f70ixkskVxZ3PMJhOXqVqX0qqUout\nRf70sc1ZP3MVqWJN8r3velJ0H/T0MCJfuwq1X38RlOMtC7R/uPEXIidE4cErDwIUcOnH34VLPv5O\nyXPTg9z+w8fetk70dVrbSpRgdDWoUiiKgt1uh91uR1NTE/94JpPhhTI3/coJJReR5hIOh4koEgrD\npU+HhoYwPj6OtWvXYt++fYruILWmT+WIorCitL29HT09Pfw56mEoXkgUjZqaUQ4KucsUpYRVqUrb\nL9hEBLGH9sNx0/1ZgijF5569Fw1tjQhNBfGtdx9ES28rNry9T+3pFsQ9H8zrP6wEjJyQoWd2wmKx\noL6+PqvfkEu/cnZ28/PzSCaTeO211+B2uxEIBFBfX6+pJzuXjo4OeDwemM1mWCwW/OlPf9Jlv3pR\n1aKoNiXGsizm5+cxNjaGjo4O2dWauZTSu5Qbmuz3+/mevty7W62FMsVEtdKnZnCibfv753C4vvA4\nqvVPUQC2A6PaI+PcqlTT6g1g5id1a9WQC5tJI/rt/bDu+xBqdl8ta5uGtsW0ZG1zHba/fxf8R32y\nRFGuM42Q8VgaP83pP6wEjIwUSy3AuenXmZkZBINBtLW1IRwO49e//jWefvppjI2N4bLLLsO2bduw\nbds2XHXVVZr6Fv/4xz9mRbGVRGUkxpcI3JDfw4cPI5FIYMWKFejq6lLdUqE1fSqVop2dncXLL7+M\nYDCI3bt3o6urS/RLrPXLttTTp9v2/SvecfUoTDINuUsBPT0MevgkLF07DT0uy7KIHboDptUbYL/y\nDlnbJKMJJMJx/t9v/PYk2jatKdk5CvsPW584jTprZVyulvssRavVCrvdjpUrV+L222/HU089hTVr\n1uCJJ57Atddei1AohIUFeWYTS5GqjxTlMjc3h4GBAbhcLmzfvh0sy+L06dOajm+xWBCNFo5QlBAO\nh3H27FmYzWZVcyKVYjKZNM+VLEQsOoRX//v9ZZuYoQQl64QcSlOXao4hBX32MNIv/AdMa/sR+sKi\nL6rjQ/fCesEVktuEAiH8nw9+a3F7msaeP78Im//sAlXHl4NY/2ElQNO0prYHJZTD4i33eIlEAg6H\nAw0NDbj00ktx6aWXajoGRVG44oorQFEUPvGJT+C2227TtD+9qWpRlEMoFMLAwABMJhM2bdrEpxm4\n0TFa0Jo+5RC2gGzcuNGwBfFyV59WFArXCdWkLvVci7Rs3Id6mdZyHCs7m/GlV7+u+FhqEes/rASW\ne6SYezOtd+Xp888/j7a2NkxNTeHyyy9Hb28vLrnkEt32r5XKyEeUiUKRYiwWw4kTJ3DmzBl0d3dj\n+/btWWXPegia1vRpOp1GIpHAsWPH0NLSgt27dxtaIbbU06d6YqpvgaVjG4DsdUIx1KQulR6j0vnW\nmzPY9Iuz2PzLs5KvEfYfsiyL35+LIJpR9/fG1OrXomGkUJVDFHOPp7cotrUtjp1rbm7GBz7wARw5\nckS3fesBiRRzSCaT8Hq9CIVCfK+hGHo0c6utPmUYBsPDw5iYmIDZbMaePXs0fXHUjsASRopyDMKX\nElpSlcXWCdWkLpUc4/BIK//vu9Ydxk+xOe815SR3qoUUYv2HlgJ/Ypd87oeY9RRoMJ+eFn24kaLw\nSwVFH8s5UqRpuqSzFKPRKBiGgcfjQTQaxW9+8xvce++9uuxbL4gonkc4GaKzsxN9fX0ldzFRmn4U\nVpS2trZi7969ePXVVzV9cbgKXDXvVRgpHnowzc+F7OzsxFUyIsjphx7Czol/UHxcpbAsi/paFgsh\nBe9RZapSzjqhmtSl0mNwfGtkr+rj6Mmmrz6R9bMTwBWhefzx4EdgMUl/Lkr6DwsKYgHmFFagG+lo\nUwmzFBcWFnQTxUAggA984AP8sf7iL/4C7373u3XZt15UtShSFAWapjEyMoKJiYmikyHE0DJoWEmk\nODMzg4GBAdTX12P37t38Qr9epuBqXf9pmsbk5CR8Ph8v1GazGRgfz3t9ZnYWlNUKc20tmEQCkeef\nBzrF961HjyPLsmAYBgzD4HvfyoCiqLzPimVZrPlp/rZq2iZUrRMqxIhjGMVcbQMuuD/bUGBFeB7/\n9Y2PKt7Xyc//m6ZzGRgYyBoIXOj7YKSjTSWIop6zFDs7O3HixAld9lUqqloUI5EI/vSnP2H16tWq\nhvxykZLaP1o5ghYKhXD27FlYrdasCRtK9iHnHNQ05obDYUxPT8NisWQJtRSZ6WlM/M3fgKVpgGFQ\ne9VVwIT4a7X0OHK9p9wEEDEx5JBzQyOnbULtOqESjDhGKZhxy7+gqo32tK5tr1ixApFIBMPDw4jF\nYqAoSnIg8HJfUyxlpLgUqGpRdLlcmof8SnkFyqHQBTkej2NgYADJZBIbNmyQ/KPUSxSVEIvFcObM\nGWQyGXg8HvT398vazt7bi86nnsp+8POKDl0UYXRIUZTmO3q5qUo91gmLofYYJisDJq389xCK16DW\noXyIdZS25qVLS42UKDLJJIb+/M/BplIATcPz7nej+dOfzntdY2MjGhvfKsbhBgKHw2FMTExkWaJx\nkyosFotuLi9SiFWDlhKxKDgcDmP9+vWGnUO5qWpRNJlMmv6oOVFUMm6pGOl0Gl6vF/Pz87JNxbWK\noty7bM7wPBgMoqenBx6PB6+99prqY+uJUAwBiEaHw1P/BIbJH777/NsK73vmwg/g/a8VTlVqXSeU\ng9pjtFw4n/Xz9V0SOWsAbel/V7x/IbfuP2iIIBYtqjkPVVODjn/9V5hcLrDpNPw33AD3pZfCuX17\nwe3EBgJzlmgnT57E3NwcxsbGkMlk4HA4+IjS4/Hoej0oh89q7vdGz/TpUqCqRVErWr1LhQjXNtvb\n27Fx40bZpuJG+qcKDc8zmUzZ+xTliCGHmCDKoYKmJJUc+pwd5paEqm0dCxHJ5+RGbHKRm2alKArU\n+SkwbCYDZDKAyhoAzhLNarViw4YNMJlMYFkW8Xgc4XAYwWAQY2NjSKVSWaObPB4P7Ha7qtqDSjAf\nr6YJGUCVi6IeMxX1EMWxsTEMDw9nF6rIRA9T70L+qYFAAD6fD6tWrco7t0roU5SzbqgHoS9crHs6\ntFR4r7pKtfCcW3ttwee/dOPWgs9f8rkfij6uNmLTA5am4bvmGqSGh9H44Q/DuW2btv2xLJ9ipCgK\nTqcTTqcTq1at4p9PpVIIh8MIh8M4d+4cEokELBZLVkRZrKAHMFYUpYoGSaRYZWiZk2e1WjXZnM3M\nzCAajSIUCskqVBGjVGuKCwsLOHPmDNxuN3bu3CmaEuLulMsJd1deamq/+rxu+3r+bQ/mPbb/hh/g\nvq9fjfWdTfinf/wjHtslPuZJDl2/EBn5JODJw8O4Zm971mMD+BVWYydcWFlw2/sey0+Xu+wzuOcD\niyOkpCI4LRGbMB17eOX585PoORQ9ttmMrqefBh0KYfSTn0TizBnYN26Uvb1SKIqCzWaDzWbL6nNO\np9MIh8N8QU80GuWjTy6izJ1xWAlFPcFgkIgiQR5qI8VQKIQzZ86gpqYG9fX1WL9+vWovRb1FMRaL\n4ezZs6BpOsvWTikrTCbMyogiaTcNc0Tdl97tSuPkyZNIp9NwOp2ora2Fx+NBbW2tYd6UevG3X7oS\nn7vr/yGdprF2bQOwq3THSq7M/nthQOOX+CvcCa+q/UUTTbLWEZVGbJwAX//YW499k/uHV74ocphr\na+Hatw+R//qvPFHcq0BkPWvX4reKj754E12ooEc449DlcsHj8SCRUJfKVoOUz2ooFEJDg7qq4KVI\n1YuilkiRm6kol1gshoGBAaRSKb6i9MSJE5pEzWKxIJlUP9yPS59yQ4jn5ubQ09OjeazLb1tbi77m\npZdewp6HW1GsQLTwuuEufl0nFAphbm4OQ0NDeUKZSqUkTQ1DoTi+9PmfY/DsFEBR+LuD12DbjrUK\n3q12evtb8fiTn+B/vvgF4449jiNoRHfJj1PKiI1JJmESyRiI9cY2feITInuQT1jHyE2qoIercE0k\nEjh9+jRomuYLerj/9L7xkxLFWCxmaAVsual6UdSCxWJBPB4v+rpUKgWfzydaUWpEoUwhTCYTZmZm\nMDw8jPb2dmzYsKHkTj7CYxeyzGJZlhfEQuuGwnWdlpYWftt4PI6pqSmcPn0aDMNgncT19+BXfoW3\nXdKNb/3TDUinMognSjf5o9EqbypKozWKubRL8f5NVuVrvCGMoxbG3QQUitjUQkkIhFhvrOed79Tl\nmKXCZDLxwjc+Po4dO3YAAF/QMz8/j5GREaTTad0KegBxUeQCBqPMCioBIooaKCZoNE3z1mcdHR2i\nFaXlEkVuNqTf74fT6VQ9KFkLhQp1tPYbZjIZjIyMIBwOY+vWrairq4P/XL7xcDicwCtHh/G1f3g/\nAMBaY4G1Rv3vQWy9UA0/v/B7BZ+/Hn+py3FaRn+KtpYUrsA7MS7RnTSAX+FXuBMMaOzArXg7Dig+\njtKILRJfoWj/UkIg2hu7xODem1hBTzKZ5Ncpcwt6uKIeOQU9gLgZeO45VANVL4paPmwpQWNZFhMT\nExgaGirqllOO5vtgMIgzZ87A6XSiq6uL/yIZjZgoKmmxEINhGIyNjWF8fFzyRkTI+Og8Ghqd+MJn\nn8CZNwPo39yKA1+8Ek7n0lqTBNS1PRRrv+DWG/8Sv0Ut1uB72I2NuBrNkGfYwKEkYvvwY39/XoS7\nVYtwNUBRFOx2Oz8QmIMr6AmHw5iZmUEsFoPZbOadecQKegDxSJG7Ka0mql4UtZAriizLYmZmBoOD\ng2hoaJBVUWpkpMi55KRSKfT19cHj8fAVsGqhKEr11AChKGoVQwCYnZ3F4OAgmpqacOGFF8qq2stk\nGJx+fRJ/+6X3YOu2Nfj6V57BoX95Hp+6O/uC/Z+r/8SvUcLxn4rOyyhK0fbArTc2njep3Yw/xxk8\nqVgUlURseoiwWvTupywHYgU9mUyGX6cUK+hxu91IpVJ5ohgOh+HxVFGjLogo6hYpBoNBnD17Fjab\nDdu2bYPD4VC8D63nIEUmk4HP58PMzAxfRMO9byWONmIUWxeUsy33n9p+Q65i1mQyYevWrbJ/9wDQ\n0lqLVS212LptDQDgiiv78f1/yW+/2Lt3L1/MU3wVuTzo2ajOkbveWIs1GMPLmvZZDD1EWC3l7KfM\nRc92J4vFUrCgZ3p6GjMzMwCA+fl5uN1uDA4Oora2VrfG/V/96le48847QdM0br31Vhw4UJkZgKoX\nRS1YrVYkk0mcOHEC6XQaGzduXIwkFGA2mxcrI1VSKFLkUomjo6OSE0AKNe/LPb5aUaUoiu8zVLtu\n6Pf7MT8/j56eHlVl400rPWhprYPfN4P1nU04/KIPXd35vXrCYh7/OWXH2NT1Zbzu/bLic1OD3o3q\n5eAv8Wv+32+XaY6bmZ2FZYWydUgxSnFjoZZS9ygKC3qAtyphHQ4HIpEIfve73+H/t3fm4VGVZ///\nTmayryRk35NJJglLIAuC1ZaqiFLEtRV9q7bWigoWS23Fyxb56atiVaS+KFBcQK2CpVKtoFWwiFqS\nGGTPJDPZ98lkm5nMPmfO7w94Dme2ZJYzC3A+18UFJJPMM9u5n/t+7vv7PXLkCLq6urB06VLMnTsX\nc+fOxY033ujxuiiKwsqVK/HFF18gJycHtbW1WLZsmdu6yYGED4peQnRAdTodJBKJ1yMM/iifkjKu\nXC7H9OnTJ22i8acijitIqXT69OloaWkBRVGIi4tDQkICM0Ix2RknObPt7u5GXl4exGKxTxm//Yzg\n03++adLbh4XFeC0Z52+4HntIQDbU6GH+r0YvEpDNxVI5xaJUchIUgdDZWATDISM8PByxsbGIjY3F\nhg0bcPjwYezbtw+PP/44jh07hlOnTjF+iJ7Q0NAAsViMoqKzFYDly5fjo48+4oNiKOLpxZTdUVpY\nWIjR0VGfZvp8DYr2qjJEGCAyMhJVVVWIioqa9Oe5CIruZor254ZpaWlIT09nhJbVajUUCgXkcjms\nVqtDoBQKhRgbG7PxleSiQch+RnAq8tNWMnOdarV6UheTs6yHUDkBKtU7IQRv4GrsIQu1GIEcY+hA\nPLJxGrtwK3wTDfcHUWWTmz97QqAVcFwRjKBof39kcD83Nxe5ublYtsw7D8++vj7k5p4vw+fk5KC+\n3r9leG+55IOiu9A0jb6+PnR1ddl0lHZ2dvr0e30NSgSDwQC5XA6DweDGRZq7+3enfDrVvCGRuoqL\ni0NWVhaA8+cdarUaAwMDaG5uhl6vh1AoRFZW1pTuIf6CnaW6O9dJp6WhbP6LTr/HZVnVH4PqQoiw\nBJvxDhaDBoW5uBdpmMHRioMDkYqbSsXGH/OUnhAKXopqtfqSEgMH+KA49QWN1VGanJzs1H/RlZCu\nO/iaKVosFhgMBnz//fcQi8VITU31aC2+inpPVT71dt6QnHfExMTAYDBAIBBg5syZiIyMhFqtRn9/\nPzQaDQA4ZJT+GjQmzVSJiYkeZan6jg7X3xx8gaPV+W9QvRRLUIolk96G2FF90Nbu031FKoWczEV6\niz82Ft4SCkGRK4eM7Oxs9PScL8P39vYiOzv0yvAAHxQnxZ2OUhLUfDUq9hR25hoWFua0icYd/FU+\n9XXEgjh0dHR0IDs7G7W1tczjYzczEe1ItVqN3t5eTEyctS8iGqgJCQmIi4vzOVCeOXMGRqMR5eXl\nXuvBOoPL88kLcVDd3tvRCgr/h6uCNpIRSgo4gQ6Kzu5PrVajoKDA599dW1sLuVzOfJ537dqF994L\nvTI8wAdFp5AWf4vFgrKysknndHwNit4EJdJEQzLX7777zutM1dcSpP36uZg3VKvVkMlkjEPHZLOe\nzrQjKYqCRqOBWq1GT08PNBoNwsLCkJrn4YNjkZqa6nEW7g75aSvdup1er0dLSwuEQiFKSkqAcf8a\nGgcLruYivSWUNhautEj9if37m6tMUSQSYfPmzVi8eDEoisK9996LGTNCswx/yQdF9puAdJSOj4+j\ntLQUKW50s3HRKONu+VKj0aClpQXh4eGorKxkRHpJYAqmKo27OqWTYTQa0draCqPRiLKyMq8zMqFQ\niKSkJBu7G4qi0KNsAO3FlGGYIAZpaWlercVXSGOXUqlESUmJzUC2L2SbQ3OX7u5cZKRS6OD24Q7J\nAgHMZvMFodIS6EzR2XOi0Wg4s41asmQJliyZvAwfClzyQRE429TR0dGBwcFBG2d5d/A1KLpzP0aj\nEXK5HDqdDqWlpQ5vUrKGYARFEpB90Sm1Wq3o7u7G4OAgioqK/JKRCYVCFGSssvmaxWJhMkq1Wg2t\nVgvBuYtmeHg4xGIxkpOTg3YBJWfZGRkZNuVjHuDG+fl4ZFwFgUDAvIZEA5Q9f8cun5MNG/k71Ank\nRtfV88FVpnghwQdFAMePH0dycjIWLFjg8YXH16A4GRRFobOzEwqFAkVFRUhPT3d6geaqg9VTaJqG\nUChET08PDAYDEhMTmdEJd39eqVSivb0dGRkZmDdv3pTP/+KhIYx60RiUHBaGf9tleyKRCNOmTcO0\nadOYjGxoaAg5OWfVbfr6+iCTySASiZjzyYSEBMTExPg1UOr1eshkMggEAsyZM2fKsZpQwtsMjuDJ\nXCQ5siCvIcG+fM4+Z2YHylCHoqiAGGiT+3L22bvUvBQBPigCAKqrq73eOYaHh3vkqegObEHx7Ozs\nKZtouAiKnnTQss8NMzIyEBcXB41GY9MROlWjy8TEBNPENHfuXLc//N4ExMl+jh2YMzMznQZms9nM\nZJNDQ0PQ6XQIDw+3CZTR0dE+B0qr1Yquri4oFAqUlJRMWr5PDgvz+rlIUSoBJ+erYel6WBXuS+Q5\n48b5+T79PBdzka7K5w4NWfner5WiKOaIwF8bpECWT11lpWq1mrPy6YUCHxThu9Gwr5kiW1R7ZGQE\nMpkM06ZNczr+4QyuOkin+gA6OzcMCwtz2ugyMTEBlUqF7u5um5JWbGwsxsfHYTAYIJFIglqa0Wq1\njNDBZIE5PDwcKSkpNkHKZDIxgXJwcBB6vR4RERE2gdITb7uRkRHI5XK3M2b7rNcdYmLP+zP+redV\n6DNsL3aZvXs9/p194Xc6fM2XkQp/zUU6a8hKVigw6sXnPvnc9YLdC0CqJuT15qLUHcjyqavjF7PZ\nzLmZcajDB0UfcddoeKrfoVKp0NHRgbCwMJsmGncQCoWcSMVNFhQ9mTd0dgEiRssdHR2Ijo4GRVGQ\nyWQBLUsSiEA6aajyZiccERGB6dOn26gZGY1GJlD29/fDYDAgMjLS5jESnVeCwWCATCYDTdMBLZX+\nT+7ZrtfXzX/j9PdyYTXlzlwkF/z7nC8hG6vViomJCZtzSoPBAIqikJGRgYyMDEaGkARFtqA9+RpF\nUT4Hysn8DblmMoPhSw0+KMI/noruYjKZoNPpIJVKUV5e7lX9XiQS+U2VhmtLpyuuuIL5oDsrS3qT\nbblr90PTNAYGBtDV1YW8vDyUlJRwGoQjIyOZ0Q2CwWBgLq59fX0wGAyIiopCfHw88z2JROJWp/OF\nQLBHKnwlLCyMee8lJiZCKpUiIyMD6enp0Gq1UCgUaG1tBUVRjJUYEY2IiIhwK1CGhYUxAXKyQBnI\n8ulkjXoXQqcul/BB0Ue8DYpsDdWoqCiUl5d77LBB8IeoNxfBUKvVQi6Xu7R0claWnCzbclVqddfu\np7GxEfHx8aipqfF6rtRTiAksGekgogRyuRzR0dGIjIyETCZDVFSUQ0YZCKIHxx3KqO5CDTpmtcGw\nmuIaq9WKzs5ODA8Po6ysjPlcJiYmMjKENE0zMoRKpRJtbW1MoCTn6fHx8czraB8kSYAknyl29YX8\nHeigaH9fRqPxkiudAnxQBBDYTJFkKx0dHcjKysKCBQvQ3Nzsc6bH1c9zMW/ILk96aulkn23RNM0E\nSpVKBTjpGnTX7mcqIQZ/wy6V1tTUMJsEmqaZrHF8fBzd3d0wmUyIjo62CZS+XqCGp0/H9HOeeQRS\nRiX8PziWzChY8H8oxT04iHhkQ4SL90KpUqnQ3NyMtLQ01NTUuMzkBAIBo9dLoGmaEbYfHh5GR0cH\nzGYzk1GSYMkOlOzPGvkMkr/JdcVbv1JPcCXx5u1G/UKGD4o+4klQHB0dtdHOJBc5LuyjjEajTz9P\ndq7sHaynH0R7SycuypMCgcA22xp0bmbojt1PsAIiew5TLBY7uKoIBAJER0cjOjoa6efOuWiaZkyN\nR0dH0dnZaXOBJX88yXh/VF/vIKvmDvbNLw/iBCLgfKThQrGasoeiKLS2tkKj0WDmzJmIZTUluYtA\nIGBslzIzMwE4vo5dXV02Gx5ngdJsNqO1tZV5bSmKYgIlu+OVy0BpsVgcqhOXYucpwAdFn3EnoGm1\nWshkMgDArFmzHD5wvmZ6IpEIWq3W658PCwuD2WxmHoc32aE/LJ08wR27n0ArhABnN0JyuRypqamo\nra11+/7ZpsYZGRkAXGcisbGxNmdbrgKlL9Nm7ja/XChWU2xI529OTo5briee4Op1ZFcGenp6YDQa\nERUVxTTd5ebmory83KnoAPuMktyHr4HSYrE4XJfUajWfKV6q+Kt8SmTjVCoVSktLXUp0+cNo2B3I\nBywxMZE5+2NnIbGxsVM+N3q9nvE/nDFjhlc7bC6ZzO7n6NGjoGk6IK4aRqMRMpkMFEU5PU/1BleZ\nCDnbGhoaYs622IEyMjIS7e3t+LPFgi/geaboCYGymgqfZsSJEyds5mE9LS+bzWbIZDKYzeaAdv46\nqwyYTCY0NzdDp9Nh+vTpGBkZQX9/v033cnx8PNN4xg6Q7LN/bwOls/GP8fFxPlPk8RxnQYMMYff3\n97slGycSiXwSAPA0KNqfG6ampiItLQ0Wi4Vpcmlvb4dWq7UZUk9MTGQ+lERtZ3h4GGKxOKjdk+7a\n/cybN89hiJuIdceF3gAAIABJREFUhbMvrrGxsV4HSqvVit7eXvT396O4uNimE9UfsM+22F6UOp0O\nKpWK2ZRFRkYG7ALnTlb56ITWp83o2bJkiUNZkt3oMlmgVCgUaG9vR2FhoUulqEBBBP4LCgqQkZHB\nrIV9ns7uXo6MjLR5jO4EStL16ipQuvJS5IPiJQpXHwjSWdjW1obMzEzGiHgqhEIhDAaD1/frSVCc\n7NxQJBIhOTnZJqNlD6kPDAww6zQajUhLS+MsC/IFT+x+XLlqkMfY2dkJrVYLoVDo8Qzl2NgYZDIZ\npk+f7lGplGvCwsKY893ExETMmTMHYWFh0Gq1iJpugWE4+B97Ls6anZUlnZ3fsQMlyZqFQuGUDiz+\nxmw2o6WlBRRFoaqqyuFMz+E8/RzsQDkwMMAIR7ADJVFYcrf0ajab+UabcwT/03GRQC6IcXFxqKmp\n8ailPhDlU29HLNhD6iqVCi0tLYiJiUFeXh50Oh2ampqYCw/JJic71/IHvtr9CIVCB/1Ms9nMDHC3\ntrY6SLuxs2Yi2G42mzFr1iyPhBe4xmKxoK2tDWq12qHbNj4+Hg93mQCYAJwfVCcbAo1Gg8NX/ThI\nK/edqQJld3c3xsfHmQDS29vLWWevpyiVSrS2tnqVqTqbhyWbV41GA4VCwbxf2YGSbOzsA+X4+Dh0\nurOenqRiFRYWBpVKxegAX0rwQdFHdDod9Ho92traMGPGDK+Ehn0NipP9PBfzhmxLp4qKCofHyG4A\nYc9s2Z/dBStz8obw8PBJs2Yi7Ua6BbOzs1FcXBy0rJmmaQwNDaG9vR15eXkuG0ZeLYyGboj99TgA\nGQFbZ6Ahz0FfXx9iY2Mxe/ZsCIXCKTNKfwVKk8mElpYW0DTNaabqTGHJZDIxGzulUgmdTsdUQOLj\n4xEXF4fBwUGo1WrMnTsXUVFRTKAcGBjAu+++i1//+tecrO9Cgg+K8K6UYzab0dbWhrGxMURHR2PW\nrFleD1xzOWdI4GLekC1QPZmlk7MGEKvVCq1WC5VK5VQoPDEx0aOzO1KaDibsC8/4+DijUZuUlISJ\niQlIpVKmizAxMTFgWYher0dzczMiIiKmvNDaBsSLGzIKo1AoIJFIbM7HJssox8bG/BIoSSMUcbzx\nNxEREQ7iGKQColQqGdPqqKgo9PT04LvvvkNJSQm6urrw8ssv44UXXsDSpUv9vs5Qgw+K53BXFJx8\n0Pr6+lBQUACJRIITJ044nfNxF66NirmYN/TU0snZmohVD4Ft6ePJ2Z1Go4FMJjtblgyyjY3JZIJc\nLofRaHTabctutx8bG+NkvtAV7E3LZN3NXPF7rY75N0VR2JgQPCGEqdBoNJBKpUhJSXHLi3Kq0qsv\ngZJ0lgoEgqCfYwqFQoyNjUGtVmPevHmIjY1lfEXb29uxfft2dHZ2oqioCJ9++imGhoZw7733XlJS\nb3xQdBNSnmpra0NaWppNE40/y5/uwO5W87VUOjExgZaWFkRFRXlk6eQOzix9JtM/jY2NxejoKPR6\nPSQSydlDfxfD+/6Gpmn09vait7cXRUVFSEtLc5k1OxvEZ88Xtre3O4xNJCQkeFReJmfYaWlpXm1a\nfEUoFCImjfYq84xJ85/QtNVqRXt7O8bGxlBeXu6TYAMXgZJ0uRYXF9s0ywSDiYkJNDU1ITU1FdXV\n1cx7RigUoq6uDp9++imeeOIJ/OxnP4NWq8WJEyfQ0tJySQVEABB4qIR+0cqmm81ml6LY7AYTsVjs\nMM/U3NyM1NRUr8cSrFYr6urqcPnll3v18zRN49tvv8WsWbMQHR3NtF57AnGxmJiYQGlpaVC7zgwG\nAzo6OqBQKJigTEqSt/vQxPJdhndnZ+T1nzZtGoqKijg5GyXlZXaTi9VqdfChtL8vkqmaTCaUlZV5\nfIb5Qqzj8+eu1RM7UwTOvu96enrQ39+PkpIS7KrJ8TJIWrGyw/vua8L4+Diam5uRmZmJvLy8gF3M\n2YGSVEKMRiMsFgvCw8NRWFiI5OTkoGWINE2js7MTSqXSYaOgVquxdu1ajI2NYdu2bUzwv0hx6w3B\nZ4qTQBzQzWbzpLtOLsqf3sA+N8zNzUVrayv0er2NgPZU4tJkrq6vrw+FhYWQSCRB3Rmyz+quuOIK\niEQipiSpUqmQaLVC5cXzlezFz5hMJrS2tsJgMHAuTMAuL2dnn5VBI92gKpXqvBEuzp/DGgwGDA0N\nMVkHF6+Tt1ZPGo0Gzc3NmDZtGjN+4u15pW4oDEePHnU6UuAOFouF6RCePXt2wLt/2Rlleno6BgcH\n0dHRgaKiIohEImbGMFDNPGy0Wi2ampqQnJxso+VK0zQOHz6MtWvX4pFHHsE999wT8GpDqMIHRSeQ\ntvbR0VGIxeIpB7B9Hb73Bvtzw5ycHKZ92pm4tH2pTiQS2Vg6zZs3L6jdoWSswWQyOQQgdknywLmv\nsZVcVCqV00zLW7UamqbR19eHnp6eSUulXMNWFCJQFMWU4Mj5cFdXF8bGxjxSHnKFp1ZPFEUxYu9c\nCqzPmjXLK9NmMviel5cX9A2d0WiEVCpFeHg4amtrmXPjQDbzEEgWPzAwgLKyMpu5XJ1Oh3Xr1kEu\nl+Pjjz9Gfn6+z/d3McEHxXOQ+Z3e3l709PRM2tZuT3h4eMCCojvnhs7siojCydDQEGQyGfR6PUQi\nEbKzszF9+vSgXUzYYtnFxcVur8WVkgspX9mr1ZCseaoAolKpbETbA63hyoa4jahUKlRWVjIBaCrl\nIU8yLU+snoaHh9Ha2ors7GzU1NRw+p7x1LQ5JiYGQ0NDAOB08D2QsH06S0pKHATfCf5s5mGj1+vR\n1NTE2KSxN7v19fVYs2YN7r33XmzevJnPDp3AB8VzjIyMMIfQl112mUcXQ5FIBL1e7/Ma2P5qzr7n\nbRMNGZmIiIjAxMQE428oEomgVqvR09MDjUYDoVBoE0DcUXHxBSLEnJaWxokCTFhYmINaDemsU6lU\nk0rXsUtw5eXlXs2bcglp6srNzXVwG3GlPEQ2BPaZljtldHfo6+sLqEaoK9Pmrq4uxoOSpmk0NTUF\nxYuSrEcqlSIyMtKrTRSXgZJUOHp7e1FWVmbT0GY0GvHss8+ivr4eu3fvRmlpqe8P/iKFD4rniIiI\nQFVVlVcfeF/PFIHzs4b2Hyou5g3Z5UB7Syf7AELKkaQTlC1InJiYyMkFh5zVCgQCv19kRSKRg1qN\nvXSdRqOBxWJBSkoKcnNzA6rGY49er0dLSwtEIpFH7fvOZtLYmRbRzQSutvk5T6yeKisrPX9AcL+R\nZyrYAegHP/gBwsPDHfw2ieME116U9hAZvZ6eHpSUlHCq/etNoIyKikJ/fz/i4uIcNpgnT57Eww8/\njNtuuw1ffvllUKsfFwL8s3OOhIQErwMbV0HRXpTX13lD4LylE2mImOwD4SwDMRqNUKlUTEnSaDTa\nSLqR80l3YIuIl5SU+H2uzhWkVBcREYGRkRGkpaUhJyeHKTH39PTYSNdxOVvoCnYZmauZQ2eGzd/Y\n3cbfVk/eNvKwIeMwfX19Ds+NM31Q+1lRdgBhnzd7GygNBgOampoQHR2NmpqagASZyazEuru70d3d\njaioKIyNjeH06dP46KOPIJFIIJVKcfjwYbzxxhuYPXu239d5McAHxXP4yz7Kk99BVGm4mDfkytIp\nMjISaWlpDueT9lZFkzW4sCXIsrOz3Rqm9idEjWhiYsKmVBoXF+f0cdrPFpLNAFfSdWTmMDU11a8z\nh87eQ/62evK0kccerVYLqVSKhIQEt0vsU5k2j4yMMF6Unmx82OXJQIglTAUZz4mIiLDp1NbpdIiN\njcW2bdswNDSEuLg4PPnkk1iwYAH+8Ic/BHXNFwJ8UOQAroKi2WwGRVE+BUN/Wzq5knRjjxKQBhdy\nvjM8PIyYmJigq3mwGyKIGpGr5zcQ0nVsdZxgCom7ayB8+vRpj7VsPWnkYUPUeoaGhhy6J73BHdPm\n9vZ2xmzXvlNbr9dDKpUiJiYmqA4oBNKRbN8db7VasWPHDvzzn//Eli1bMG/ePNA0jfb2dsjl8iCu\n+MKBD4oc4GtQJF5no6OjiIiIQEREhFfnhoODg+js7Ax4NuZslICcGyqVSsTExECtVuPUqVM2ZddA\nNWwAZ+fqWlpamI48b0qhU0nXdXV1YWJiYsqGJXIe1d3dHdCRD1/Jy8tjOkHtNwRnX3tugrparUZz\nczNjweXPzHkq02Yyp0pRFDIyMpCenu6WHKS/MJvNaG5uBgCH93FXVxdWrlyJOXPm4JtvvmGEHQQC\nAYqLi1FcXOz1/fb09ODuu++GQqGAQCDA/fffj9WrV9vc5tChQ7jxxhtRWFgIALjllluwbt06r+8z\nWPBB8Ry+XJSEQqFLNZypIOeGWVlZ6O/vx8mTJxmHCXaZbrILAxkjiI+PD4lsjFzw8/PzMXv2bOa5\nZTd+2J9P+uvcjl0qlUgknM3VEVxJ15GOV3vpuoiICCgUCqYceCE1PTiboSQVgu7ubjhz2/CkkYei\nKMb2imuxBHdhj/okJSVBKpUiLS0NmZmZmJiYgEKhYI4lAu0CQ+ym7AXFrVYrdu7cie3bt+Mvf/kL\nfvSjH3F+3yKRCC+99BKqqqqg0WhQXV2NRYsWoaLCtgx+5ZVX4pNPPuH8/gPJhfOJvMiwPzeMi4uD\nRCIBMHk5kowcREdHM4orRqMxJMYISHBOSEhwmo05a/zQ6/VQqVQ253bkYkO8Gb0dwCeZc35+fkAH\nu53ZTpHMeWBggGmIOHXqVEDdNLjG3rD5Uye3cbeRZ3R0FDKZDNnZ2Q4jKIGGLV/HHm1gl3DZpfSB\ngQHIZDK3ZPq8wWw2QyaTwWKxOGx6BwYGsGrVKuTn5+Prr7/mfNNHyMzMZLLp+Ph4lJeXo6+vzyEo\nXgzwQfEcgdRJnKqJxlk5kj0uoVAooFKpQFEUpk+fjtzc3KBeUMnZmMFg8Cg4s895nJ3b9fX1QaPR\nQCAQeDSAT0qlxPA5mCMWwPkdfk5ODpM5szskR0dHGTcNZ+dZFzLuNvJ0dnaisrIyaH6UBNLYQ8Qb\nXAU1Z6V0tmkzee8CYG7njcrSyMgIZDIZCgoKkJGRYSP+/8EHH+Dll1/Ghg0bcP311wfsGtbZ2Ylj\nx47hsssuc/jekSNHUFlZiaysLLz44ouYMYO7pq1AcWF/4kKMqYbvfZk3JPN2FosFCoUC+fn5SEtL\ng0ajwfj4OLq6umA2mx2yLH+WdIgCUH9/PwoLCzk5G3N1bkc2BO3t7YyruP38JLv8xrhqBBGDwYCW\nlhaEhYU5qK646pC0P8/iSroOOHtWx9W5nye408hDJNLYmXMgh/BpmmZGYrxt7HEl00cCJdGzJSVa\ndkZp/5paLBZmo0kMgAlKpRJr1qxBTEwMDh06FNAu2ImJCdx6663YtGmTw+erqqoKXV1diIuLw/79\n+3HTTTddkM09vEsGC5PJ5PUhekNDA+bOnes0K7GfN/QmcBBPwaioKIjFYqcXDHJRValUjB6op1mW\nu4yOjkIul2P69OkoKCgIeDeeyWRi5idVKhW0Wi3MZjOSk5ORk5ODxMTEoGWI7JlDXwe72aV04sJA\nNg7sjtfJXlOi5avRaFB32w+gV3r+WsWk0VjZMblqkzMHDnd5dEJrc+ZMnCb8PYQPnBfNJi4o/m5Q\nYzdnqdVqRmWKvKYA0N3djby8PGRlZdlkh/v27cPTTz+NJ598ErfeemtAy8xmsxlLly7F4sWLsWbN\nmilvX1BQgMbGRpeyd0HArSeLD4osfAmK33//PcrLy23KP1zMG5pMJrS1tUGr1Xpl6cTOstRqNbRa\nrY38l6cqNWT+kaZplJaWBr3cRfwfo6OjmQF88njZ55OBaoYYHx9HS0uLXzcL5DUlj1On0zHne/ba\np6R0m5ubi+zsbL9eRH0Jiva2VIDtbCH5w2WJmaZpxqS5vLw8qJUFi8UClUqFjo4ORoowPDwcer0e\np06dwsyZM/Huu+9Cr9djy5YtNo02gYCmadxzzz1ITk7Gpk2bnN5mcHAQ6enpEAgEaGhowG233Yau\nrq5Q6qzmg6KnTOapOBUnT55EYWEh4uPjOQmG9pZO5M3GBWxZLJVKxah9sC+q9hcaiqKYuTGuZa28\ngS2WXVpa6rTcxT6fJFkWyZzdzbLcxWw2M+WusrKygM8cErNm8lh1Oh3MZjPCw8NRUFCAlJQUv5cj\nuQ6KzmCXmMlr6s3mZ2JiAlKpFMnJySgsLAy6MLZKpYJUKkV2djZycnIgEAgYPd7Nmzfjv//9L/R6\nPfLz81FdXY2f/OQnuOaaawK2vm+++QZXXnklZs2axTxXzz777LmuY+CBBx7A5s2bsWXLFohEIkRH\nR2Pjxo1ee8T6CT4oeoovQbGpqQkZGRlISkrySacUOO9GkJqaGpDSJNtFg1xsaJpmggdFUejv70dW\nVhZyc3ODegGhaRoKhQIdHR1eZT+kdMXOnEUikcP8pLu/ky0IwPXmxRvYqit5eXmM6Dt78+OvEZhA\nBEVnsA2bVSoVJiYmQNO0Q6AMCwtjRAGcGe4GA6vVylhxVVRU2GymJiYm8Kc//QmdnZ14/fXXkZub\ni/HxcXz//fcQCAT48Y9/HMSVX5DwQdFTLBYLI7XmKeS8LyMjA2FhnjvfA2fPNmQyGUQiEUpKSgI6\n3G6P1WplpNkoioJQKHRwXfAkeHCBVqtFS0sLc67K1fkSWyBcpVLBYDAgKiqKeZyuzidJ6TY2NhbF\nxcVB73KdmJhAc3MzEhISUFxc7LCZYo/AkMdLpOu4aM56tTDaK6Nhd84rPYXd4ELO7axWK0wmExIT\nE5mqTjA3eBqNhpmDzM/Pt/ks/fe//8Xvf/973H///VixYgXn6/zss8+wevVqUBSF++67D2vX2oq0\nG41G3H333Th69ChSUlKwe/duFBQUcLqGIMAHRU/xJiiSUqlKpUJXVxdzZse+oE5VtjKbzejo6MD4\n+DhKSkpsHB2CgcViQUdHB8bGxlBaWsrMaZnNZqbkqlarYTAYEB0dbVN29UdgIMa2Y2NjkEgkPkt+\nTQV7XII8Vrb8V3x8PIaHhzE+Ph6Q9UwFRVHo6OjA6OgoysrKPDobc5Vl2c/beXJRtlqt6OjowMjI\nSMhkYx0dHRgeHkZubi5TatZqtRAKhTaZs7/t0sh6iBRjRUWFzQiTwWDA//7v/+L777/H66+/DrFY\nzPn9UxSF0tJSfPHFF8jJyUFtbS3ef/99m5nD1157DSdPnsTWrVuxa9cu7N27F7t37+Z8LQGGD4qe\n4klQnOzc0NmZHRGSZu/G7S2d2J1mwYA98O5OaZIED3ag9FSNZ6r1kGw1JyeHOWsJBuQsq7e3F4OD\ng0zmzO7sjYuLC/j6yNB7ZmYmZ6VtV92R7CqBq+BBGo3S09ORl5cX9LM6ko2lpqYiPz/fYT1EfYjd\ntETGffxRESFnmSkpKSgoKLBZz7Fjx7B69WosX74cv/3tb/12bHLkyBGsX78e//73vwEAzz33HADg\n8ccfZ26zePFirF+/HgsWLIDFYkFGRgaUSmUoNc14g1uL5+cUWbjzgrNnDV2dGzpTbrEXkqYoCmaz\nGQkJCZgxYwbi4+OD+oZTq9WQyWQeDbyzZ+2IyLIrNR525uyOKzwplUZGRgZdug44u9Fpa2uDQCDA\nggULmLlIckHt7Oy0OZ8kj9VfJWYimGAymTgfencmXUfEI9RqNWPGTMrpZNSnt7cXWq02qOLmBHJW\nNzY25pCNsXGmPmTvt6nX6218Rb3R7WV3ulZUVNhkz2azGS+88AK+/PJL7Ny50+8D7319fcjNPS/S\nnpOTg/r6epe3EYlESExMxMjISCiNV/gNPih6gLf+hmw9xeTkZMjlclAUhcLCQhiNRnR0dDCGvuzg\nEYhAQEY+dDodJ9qg7qjxkIuMs8fKLgWyS7fBwmq1oqenBwMDAw5dt650T8ljHRwchF6vR1RUlE3m\n4cvrys7mAykm7sxrk8yKDg4OQqlUQiQSIT4+HgMDA5w8Vm9Rq9WQSqVIT09HTU2Nx88P8dtkBwBS\nTmfr9rLPnSd7rDqdDk1NTUhKSnIQOG9qasKqVatw3XXX4auvvgr6uTQPHxRtmEyNxtcRC3KxHxkZ\ncWnpREqRRKGGnGOxy65claOIcWtvby8KCwtRVlbmt4urswuq/WM1m80QiUTQ6XTIzMxEVVVV0CXO\nVCoVWlpakJKS4rZdUHh4OFJSUpjXlzjDq1QqjI2N2ci5sS+o7vxunU6H5uZmxtw22BdQgUAAhUIB\niqJw+eWXIzIy0sbcN9DSdVarFW1tbRgfH8fMmTM5FRSfysiYPFZ7I2OFQoG+vj6Ul5fbnD1TFIXN\nmzfjH//4B7Zt24bq6mrO1joV2dnZ6Ok5L9Le29uL7Oxsp7fJyclhZiiDPYYVKPgzRRZWqxVms5n5\nPxfBkL2zz8nJQXZ2ttuBjT1nRxRqvClF2jM2Nga5XM7MaAXbG45c7AUCAaZNmwadTudXNZ6pMJvN\nTImwrKyMc7cG9qwdeV3ZzS32voxsb0GJRBL07Jl91jtVtmo/V6hWqxmHCS7OnQkqlQrNzc3IyMhA\nXl5eUI4i2P6Mo6OjGBoagkAgQHJyMhITE5nXb3h4GCtXrsRll12Gp556KuBd5haLBaWlpTh48CBj\nM/fee+/ZlG1fffVVnDp1imm0+fDDD/HBBx8EdJ1+gG+08RQSFN05N3QHtqUTVy377FKkSqViynMk\nm5ysA9RgMEAul8NisUAikQT93IdtiFxaWurQdetKjceTzl5PYG9g7AWY/Q3bhok0twiFQkRGRkKt\nViM1NRVisTjoGxiDwYDm5maEh4ejtLTUq/c0WzibdLyyRRU8aVpi693az/kFA2Kd1tPTw3Qmk03B\nCy+8gEOHDmFoaAiXX345li5dipqamqBURfbv349HHnkEFEXh3nvvxRNPPIF169ahpqYGy5Ytg8Fg\nwF133YVjx44hOTkZu3btQlFRUUDX6Af4oOgppNTlq06p0WhkmiBKS0v9aunkqgOUnXXExMSgp6cH\nCoUCxcXFNk7dwUKpVKKtrQ1ZWVnIyclxO1OYTI2HlJi9ucBotVo0NzcjJiYGYrE46KVJi8UCmUwG\ntVqNadOmQa/XT3oW62/YogD+UDRiS9fZj0uQx2tfFRkfH0dzczMjKhHszkij0YimpiZERUWhpKTE\n5n3Y19eHlStXQiwW45lnnkFHRwe+++47NDY2YsOGDZdMaTLI8EHRU3bv3o1//vOfqKmpwbx58zBr\n1iyPLjoURaG7uxsKhQJFRUVITU0NygeV3QE6NDSE8fFxREREIC0tDUlJSUyGFYy16fV6tLS0MAIF\nvmZ6U6nx2Jci7WE39oTCzCEADA0Noa2tDfn5+cjMzLR5neznJ8m4D3v4nuusQ6fTQSqVIi4uLqDZ\nqr10HdkUxMXFQavVwmKxYMaMGSGRHRKVpdLSUpsAZ7VasWvXLrzyyit48cUXsWjRoqAH70sYPih6\nitlsxokTJ1BXV4f6+nqcPn0asbGxqKmpQW1tLebNm+d0lpCmaSiVSrS3tzNnGsGez9LpdJDJZBAK\nhSgpKYFQKHQ5eE924v4s4RDtVKVS6bRUyvV9kU0BcdBgG+KSlvqRkRG0trZ6nK36C2I1JRQKUVpa\n6taGzNWmgH1m5+nwPYG4fSgUCq/tlLhGoVBAJpMhNjYWNE3DZDIFREDCFSaTCVKpFCKRyKGcPDQ0\nhNWrVyMpKQmbNm3yuyjH73//e/zrX/9CREQEiouL8dZbbzk9fy4oKGBmpUUiERobG/26rhCCD4q+\nQtM0RkdHUV9fjyNHjqC+vh4DAwMQi8Wora1FbW0tKIrC22+/jd/+9rcuLZ0CCbvLdbLgw5b8IhdU\ndoaVlJTEWWML0XLlcsDcU8jsGekC1Wg0EAqFyMjIQEpKSsAvpmzYTu9clCatVqvNQDo5n2TPT07V\noEWG3lNSUkJCMJuiKMjlcuh0Ohs3GmfSdRaLJSC+oiSjF4vFNkcSNE3j448/xrPPPounn34aN954\nY0Cyw88//xxXXXUVRCIRHnvsMQDA888/73C7ELR0ChR8UPQHFEWhpaUFn3/+ObZv346xsTGIxWKU\nl5czZdfi4uKAX0TYJRxPu1wJ7GF0kmGx1T28sZmSyWQICwsLupYrYBt8iouLERsba1OeY6vxJCYm\nep1heYJGo0FzczOSkpJQVFTkt9IkUW5hu2iQgXSSZRFBAiJQXV5e7tfzcHchqj3kfT1VgGFL1xEn\nDa6yZ+Dsc9nS0gKr1YqysjKbjH5sbAyPPvooLBYLXnvttaCd3+/duxd79uzB3/72N4fv8UFxihvx\nQdFzBgYGcP311+Pxxx/HT3/6U2i1WjQ2NjLZZHt7O9PqXFtbi5qaGiQmJvptt0gMiKOjozkVygbO\nD2jbS9axL6b2F3IyQqBQKFBaWhpQZ3BXkJnDycZQnBn6epphuQs7+JSVlQVFH5Q9kE46mc1mM5KS\nkpCXl4fExMSgzooS93m9Xo+KigqfNlXOunvZQhOkIW2q13Z4eBhyuRyFhYWMihNwdsN14MAB/OlP\nf8Jjjz2GO++8M6hnhzfccANuv/12/PznP3f4XmFhIaZNmwaBQIAVK1bg/vvvD8IKgwIfFP2JyWRy\nGXzIWcyRI0dQV1eH7777Dnq9HrNmzWICZUVFhc8XHLPZzDiqSySSgJikss+wyAUGAHNhoWka3d3d\nyMzMDImzVfIcabVaSCQSjzMfdoZFAgfpAPVWtWVkZARyudzGOy+YkOCj0+kYlSXy2lqtVpumpUBk\nz8D55ygvL8+h2Ygr2NJ1pOM1PDzc5nySyPSRbmCTyYTy8nKbiolGo8ETTzyB/v5+bN++3WEQnkuu\nueYaDA4OOnz9mWeewY033sj8u7GxER9++KHT562vrw/Z2dkYGhrCokWL8H//93/44Q9/6Lc1hxB8\nUAwljEYjjh07hrq6OtTV1UEqlTKyT+SPu158bCHxQM/TOYOiKAwPD6O9vZ1RpmFLmwVydIDAnjl0\n1sXpy+/feJaSAAAfBElEQVRlBw2VSgWz2ewwjO4sEzWZTJDJZKAoChKJJOjlZODsaExra6vL58hZ\n9uyuOLg3ELNmo9GI8vLygD9HpDJCAqXBYIBQKIRer0dGRgYKCgqYgEjTNL755hv84Q9/wMqVK3Hf\nffcFfRO4Y8cObNu2DQcPHnSrK3f9+vWIi4vDo48+GoDVBR0+KIYyRBWkrq4OR44cQUNDAzPETjpd\nKysrHS4K4+PjkMlkzBlUsKXQ2KVSdpMICRzkDztwcC1ZZw/bd7GkpMTvDTQ0TdsMoztT4xkfH0dP\nTw+Ki4sZqbBgYjKZ0NzcDACQSCQenRWzMyziLMGFqAIpTYbCRg84u9mTyWSYmJhAZmYm09Dz+uuv\no6enByKRCMPDw3j77bcxa9asoK4VOOuRuGbNGnz11VcuzzK1Wi2T/Wu1WixatAjr1q3DddddF+DV\nBgU+KF5oWCwWNDU1MWXXkydPIjw8HNXV1SgtLcX+/ftx5ZVXYsWKFZxLj3kDKXGlp6c7teVhQwIH\nO+MQCAQ22aSv53VshZxgy6GRYXSlUomBgQGm0SMpKckvajzuws6guQzQbFEFtVoNo9HI6IBONfJj\nNpshk8lgsVhQVlYW9A5u4LwwgLPmnvr6evzxj39EUVERkpKScOzYMej1evzlL3/BFVdcEbQ1i8Vi\nGI1GZmM6f/58bN26Ff39/bjvvvuwf/9+tLe34+abbwZw9npz55134oknngjamgMMHxQvdGiaxvDw\nMP74xz/i448/xuzZsxkBb5JNVlVVBdzHz2AwQCaTgaZplJaWem1b5ItknT0kQAdz7IMNMZJVKpXM\njN9UajzuCoN7i16vR3NzMyIjI/2eQTsblXDmtUlmRQsLC90+PvAnRFRcrVajvLzcpgRpMpmwYcMG\nfPPNN9i+fTvKy8uZ75nNZlAUFRIlcR6X8EHxYmDjxo3QarV49NFHER0dzXxoSTb5/fffw2w2o7Ky\nkjmblEgkfrm4kgaiwcFBiMVizlu67R3vVSrVlGMSRqMRMpkMVqs1ZM7p3DXadUeNh4sND3sUJZjd\nwGzN07GxMYyMjAAAUlNTMW3aNLc7QP0FsZwiGyv2Os6cOYNVq1bhhhtuwGOPPeb3kvz69euxfft2\npgz67LPPYsmSJQ63++yzz7B69WpQFIX77rsPa9eu9eu6LnD4oHipoNPpcPToUUaJRyaTIS0tjZmb\nrKmpQUpKik8Xm9HRUcjlcqSmpjo4hvsTdqOH/SC6xWLB+Pg4SkpKQuKcjrhr6PV6lJWVeSU/5mxW\nlBgXs2dF3X0tidO7v+cgPYEMvRcVFSElJcVmfpKIvrPLrv7e6FitVkbqr6KiwuZowmKx4JVXXsHH\nH3+Mbdu2Ye7cuX5dC8GdBhiKolBaWoovvvgCOTk5qK2txfvvv4+KioqArPECxK0PDe+neBEQExOD\nK6+8EldeeSWA80r9R44cwX//+1+8/PLLjIsAKbvOnDnTrY5QkolRFIXZs2dz6vDuDuxZMuIEPjo6\nCqlUioiICERHR6OtrQ39/f0Bk6yzh22lVFBQ4JM3pTPjYrYaT39/v41EnytpM1K+HR4eRllZWUDG\ndabCZDKhpaUFNE2jurqaef9NmzbNRnmJ3QFKDH39JeU2MTGBpqYmpKamorq62mazJ5fLsWrVKlxx\nxRX4+uuvQ+Ksk01DQwPEYjHjXrF8+XJ89NFHfFD0ET5TvEQwm804efIkIzBw+vRpxMTEMNmkva6r\nyWRCX19fSDlrWCwWtLa2YmJiAmVlZczMoTPJOtJhxy67+qMsR87pIiIiUFJSEpDRk6nO64RCIbq7\nu91qgAoUCoUC7e3tXjX3kMfrTH2IXWb2JAumaZo58y0vL7cRT6AoCq+//jreeecdbN68GZdffrlH\n6+WC9evXY8eOHUhISEBNTQ1eeuklB8nGPXv24LPPPsPrr78OAHjnnXdQX1+PzZs3B3y9Fwh8+ZTH\nNZPpumZmZuLgwYNYt24dbrjhhqCPfbAl7NydOST6n2xRcJFI5CAK7suauru7MTAwEBKqPVarFSqV\nCu3t7ZiYmEB4eDjzeLlW4/EEMvoRFhYGiUTCWYbHNuBmdzO7Y0qt1WrR1NTEqBuxNw09PT146KGH\nUFFRgeeff96vDhyTDeLPnz8f06dPh0AgwJ/+9CcMDAzgzTfftLkdHxQ9hg+KPJ7R39+PBx98EF1d\nXZg7dy5Onz4NAKiqqgqarqtOp0NzczOioqJ8lrBjl+VUKhUzNuBp96darUZzc/OkknGBxplKDrFe\nYsu4+arG4y7sjYy9YLa/IOexZCOk0+lsNgYJCQkYGhrC4OAgysvLbUrKVqsV7777LrZs2YKXXnoJ\nV199ddA7YQmdnZ1YunQp83kkHDlyBOvXr8e///1vAMBzzz0HAHj88ccDvsYLBD4o8njGn//8Z5SX\nl+OGG24AcH62kOi6NjQ0MMbA8+bN86uuK3ukwV8zh/aSdUQ4mt3kwc422C7v7PJtMCEzfkR+bLLs\nl63GQzYH7qrxeILRaERzc7NTO6VAQ85jR0ZGMDAwAADMpkCpVKKoqAgUReE3v/kN0tLS8PLLL4eE\nRdbAwAAyMzMBAC+//DLq6+uxa9cum9tYLBaUlpbi4MGDjNbye++9hxkzZgRjyRcCfFD0lttvvx0t\nLS0AzrbXJyUl4fjx4w63uxR9ySbTdSXZpK+6rsQVIRjelPbZBumGDA8Ph1qtRk5ODvLz80MiiyDn\ndL7M+E1VhvRkTIItDFBSUhISLgxEErG3t5eZFyVjP1u3bsUnn3yC/v5+VFZW4qabbsJll12GuXPn\nBn2056677sLx48chEAhQUFCAbdu2ITMz02YQHwD279+PRx55BBRF4d57772UBvG9gQ+KXPC73/0O\niYmJWLduncP3LmELFhuMRiOOHz/OBEpvdV2NRiPkcjksFgskEknAO11drampqQlmsxkJCQnQarWM\nUwhbsi6QJVSSiXliRuwJRI2HXYacSsbNYDBAKpUGRBjAXQwGA5qamhATE8MYbRNGRkbwu9/9DkKh\nEC+//DKUSiUaGhrQ0NCAFStWoKqqKogr5/ETfFD0FZqmkZeXhy+//BIlJSUO3+eDonPYuq5kdnIy\nXVdiIDs2NhYy2qBs0XVnJrIku2JrnXIpWedqTf39/eju7g54JmYvgs5W4zGbzUyZ21eDZC6gaRoD\nAwPo7u52aIKiaRqfffYZ1q9fjyeeeAK33367X7N+vuoUUvBB0VcOHz6MNWvWuHyDXsK+ZB7jSte1\noKAAJ06cwM9+9jOsWbMmJDKMiYkJNDc3Iz4+HsXFxW6VgtmSdWwTXxIkExMTfXpsOp0OUqkUsbGx\nEIvFIdERPDY2xswdkiyMazUeTzEajcwMa2lpqc3zpFar8fjjj2N4eBh//etfmTO7QMFXnYIOHxQn\nwx1fsgcffBBisRi/+93vnP6OS9iXzGfUajXWrl2Lb7/9FgsXLkRrayu6urpQUFAQNF1XIig+MjLC\nycC7wWCwcQpxpv051XkpTdOMC0mwRc7ZayLndOxMjGs1Hk8hZ6z2WTRN0/j666/x2GOPYfXq1fjF\nL34R8NlNvuoUEvBB0RcsFguys7Nx9OhR5OTkTHn7S8yXzGf27dsHhUJhc4Eiuq6k7Hr06FGYTCbM\nmTPH77qupLnHn4Li7KYWUnYlknUkaBBTW+CseW1zczOmTZuGoqKikBjC1+v1kEqliImJcStjZavx\nkDEYtjpNYmKiz1nvZLOQOp0OTz75JFpaWvDGG28gPz/fp/vyFr7qFBLwQdEXPvvsMzz33HP46quv\nnH6fC18yXvR3alzpulZXVzNjIb7ourJHGsrKygLe3ENmCUnQMBgMiIqKAkVRzJiFvZJJMKBpGr29\nvejr64NEIvF6Ta7UeOzLru5uAIhJsrOz6IaGBqxZswa//OUvsXLlSr9tKviq0wUDHxR94Re/+AXm\nz5+PBx54gPka175kvOiv57B1XUmg9EbXlT0+ECq2RQAwNjYGqVSK+Ph4hIeHQ6PRMEGDZJOxsbEB\nzRr1ej2ampoQFxcHsVjMeaY+mei7KzUetgdjeXm5zettNBrx7LPPor6+Htu3b4dEIuF0vZ7CV51C\nBl4Q3Bd27Njh8LWsrCxmPqioqAgnTpzw+zp40V9bBAIBsrOzcdttt+G2224DcF7Xta6uDtu2bZtS\n13VoaAi9vb2IiopCTU1NSDT3EF1XrVaLOXPm2MiLsSXrurq6MDEx4XBW54+5OrblVFlZmd/OM52J\nvrPVeBQKBeO1mZCQAIFAgMHBQRQWFiIjI8MmWJ48eRIPP/wwbrnlFnz55ZdBb0gCgAMHDqCsrMxl\nQLSvOn3++edOm3F4AkPw3zGXOJs3b8bbb7/tUvS3r6+PuVAAQE5ODurr6wO9zJAmPDwc1dXVqK6u\nxsqVKx10Xd9++2309/czG4uWlhb885//dPDMCxbDw8OQy+XIy8uDRCJxWFNYWBgT/Ajss7q+vj6v\nJetcodPp0NTUhISEBNTW1gZcyi48PBwpKSnMiAcZg2lpaYFer0dERAQ6OzsxMDCATz/9FLW1tWhs\nbMSBAwfwxhtvYPbs2QFd72Ts2rULd9xxh83X2FUnhULhUHXy5BiGh1v48qmf4UV/Q4O6ujrcf//9\njOPHsWPHAJzXda2trYVYLA5oWdJkMjG2XGVlZT5ZE01mWMwuu061CSBC54ODg4wCTChAxj9yc3OZ\nrN9qtWJ4eBhbtmzBgQMHMDAwgLy8PNTU1OCyyy7Dz3/+85DY9PCEDHz5NBQ4cOCAW7f79a9/jaVL\nlzp8PTs7Gz09Pcz/e3t7kZ2dzdn6LgVomsbu3bvx97//nTlfIpkH0XVdv349WltbkZ2d7XddV/Z5\nZlFREdLT033+nQKBALGxsYiNjUVWVhYAW8m69vZ2RrLOlTKNVquFVCpFYmIiampqQkLonOjNajQa\nVFZW2jRC0TSNv//97zhw4AC2bNmCefPmYWJiAt9//z3OnDnDB0Qer+AzxSASSNHf3//+9/jXv/6F\niIgIFBcX46233nJ6RnQpK2vY67o2NjZCp9NxqutK5NDIcHmgzzONRqNNtyuRrKMoCjqdDhUVFSHR\n7QoAKpUKzc3NyMrKYpw/CF1dXVi5ciUqKyvx7LPP+qVr+O9//zvWr18PqVSKhoYG1NTUMN977rnn\n8MYbb0AoFOKVV17B4sWLHX6+o6MDy5cvx8jICKqrq/HOO+8ExG+TxyV892moE0jR388//xxXXXUV\nRCIRHnvsMQDA888/73A7fojYFq50XdkjDaHgv0jQaDQ4c+YMIiMjERkZaSNZR7JJdwXBucJqtaK9\nvR3j4+OoqKhwaDrauXMn/vrXv2LTpk348Y9/7Ld1SKVShIWFYcWKFXjxxReZoNjU1IQ77rgDDQ0N\n6O/vxzXXXAOZTOaQWf/sZz/DLbfcguXLl+OBBx5AZWUlHnzwQb+tl2dK+KDI45y9e/diz549+Nvf\n/ubwPT4oTg7RdWWbMxPdT2e6rsBZYYD29nYkJCSguLg4JMqSVqsVXV1dUCqVDuo9zgTBA+XDqNFo\nIJVKkZaW5uBGMjAwgFWrViE3NxcvvfQS4uPj/bIGexYuXGgTFO19CxcvXoz169djwYIFzM/QNI3U\n1FQMDg5CJBI5eB/yBAX+TJHHOW+++SZuv/12p98TCAS49tpreWUNFwgEAqSnp2PZsmVYtmwZAFtd\n13feeQePPvoowsPDUVlZifHxcfT09GDPnj0hIdEGnNV2bWpqQkpKCmpqahyai4RCIaZNm2ZTRiWS\ndWNjY+js7ITFYkFcXByTTbojWTcZxD9zeHgYFRUVNl6V5Oxw48aN2LBhA66//vqgnhf29fVh/vz5\nzP9zcnLQ19dnc5uRkREkJSUxpXZnt+EJTfigeBHhjrLGM888A5FIhP/5n/9x+ju++eYbG2WNsrIy\nXlljCkQiEWbPno3Zs2djxYoVoGkaX331FR588EHk5eUhKSkJ1157LaPrWltbi+rq6oALZrMDT3l5\nuUeZVlRUFKKiopimILZkXW9vLzQajc3oiL1k3WRMTExAKpU6DdJKpRJr1qxBdHQ0Dh06xHnZ2Z3P\nDM+lBR8ULyKm6nTdsWMHPvnkExw8eNDlxYp0tqalpeHmm29GQ0MDHxQ9xGw247XXXsPevXtRVlYG\n4Pw52ZEjR7Bv3z489dRTAdN1Bc6XJVNTU51mh54SFhaG+Ph4xMfHM0PpFouFGQkZHBxkBu7ZZVd2\nYxEROx8aGnII0jRNY9++fXj66afx5JNP4tZbb/XLBsLd7nA27nSEp6SkYHx8HBaLBSKRiO8av4Dg\nzxQvET777DOsWbMGX331lY03IBtf9Vyn0mg1Go24++67cfToUaSkpGD37t0oKCjw9aFdsBBd1/r6\netTX16OlpYUJWlzougJng3FHRwdGR0dRXl5uU5b0NzRN2ziFsHVOo6KioFQqkZKSguLiYpsgPT4+\njsceewwajQbbtm3jZGTFF+zPFM+cOYM777yTabS5+uqrIZfLHTY0P/3pT3HrrbcyjTazZ8/GQw89\nFIyHwHMWvtGG5zxisRhGo5FRCJk/fz62bt3KmZ6rOxqtr732Gk6ePImtW7di165d2Lt3L3bv3s39\ng71Asdd1bWhogEqlYnRda2trMWvWLLebXNRqNaRSKdLT05GXlxcSLhsURaG9vR0DAwOIi4uDyWSC\nUCjEt99+y3S6bty4EY8++ijuuuuuoK557969ePjhh6FUKpGUlIQ5c+YwjTLPPPMM3nzzTYhEImza\ntAnXX389AGDJkiV4/fXXkZWVhfb2dixfvhyjo6OYO3cu3n33XZ8EGnh8hg+KPIHDvrvOvkMPsO3S\ns1gsyMjIgFKp5IesJ8FsNuPUqVNMoDx16hRiY2Nd6roCZwNPR0cHxsbGUFFRgdjY2CA+gvMQ2yli\nlEwyK7PZjH379mHnzp1oampCfHw8JBIJ5s+fj+XLlwfN7onnooPvPuUJHO5otLJvIxKJkJiYiJGR\nEX78YxLCw8NRVVWFqqoqG13XhoYGG13X4uJi1NbWIi4uDjt27MAbb7yBmpqakNhwkAy4p6fHqe1U\nY2MjXnjhBfz617/Gp59+CoFAgPb2dtTV1cFoNAZp1TyXKnxQ5OG5gBAIBEhJScH111/PlOysVitO\nnjyJxx9/HKdPn0Z+fj5WrFgRVF1XgtFoRFNTE+NIwlYDMhgMeOaZZ9DY2IgPPvjAxpG+uLgYxcXF\nnKzBlTLNF198gbVr18JkMiEiIgIvvPACrrrqKoefd9f3lOfigA+KPJzgTkceuU1OTg7TqUjOOHm8\nJywsDBs3bsSSJUuwb98+CAQCB13XtrY2ZGVl+V3XlcDWdy0tLXV4nY8dO4bf/OY3WL58Ob788ku/\nChrMnDkTH374IVasWGHz9enTp+Nf//oXsrKycPr0aSxevNjlLOFvf/tb3t/wEoEPijycUFtbC7lc\njo6ODmRnZ2PXrl147733bG6zbNky7Ny5EwsWLMCePXtw1VVXeX1R7unpwd133w2FQgGBQID7778f\nq1evtrnNoUOHcOONN6KwsBAAcMstt1y0PnU7duywyQTj4uKwcOFCLFy4EMB5Xde6ujp8+eWXeP75\n56HT6TBz5kxGicdXXVeCyWSCVCqFSCRy8Ks0m8144YUXcPDgQezcuRMzZ870+f6mory83OnX586d\ny/x7xowZ0Ov1MBqNfDPMJQ4fFHk4QSQSYfPmzVi8eDGj0TpjxgysW7cONTU1WLZsGX71q1/hrrvu\nglgsRnJysoP4uaf399JLL6GqqgoajQbV1dVYtGiRg/nylVdeiU8++cTXhxfyTFUaDQsLQ0FBAQoK\nCrB8+XIAtrqumzZtQnNzMxITE5lMct68eW7purIZGhpCW1sbxGKxw+hPU1MTVq1aheuuuw6HDx8O\nCXNnwj/+8Q9UVVW5DIhT+Z7yXDzw3ac8FwU33ngjVq1ahUWLFjFfO3ToEF588cVLIihygTe6rgSz\n2YyWlhZYrVaUlZXZjI1QFIVXX30Ve/bswdatW23cJrjCHWUa+3lDwpkzZ7Bs2TJ8/vnnTs8xFQrF\nlL6nPBcE/EgGz6VBZ2cnfvjDH+L06dM2wtaHDh3CrbfeipycHGRlZeHFF1/02HLrUofoutbV1aGu\nrg4nTpxgOmJJoGxsbMSZM2fw4IMPOgzad3R04KGHHsK8efPw9NNPOw2ogcJZUOzt7cVVV12Ft956\nCz/4wQ+m/B2dnZ1YunQpTp8+7c+l8vgHfiSD5+JnYmICt956KzZt2mQTEAGgqqoKXV1diIuLw/79\n+3HTTTdBLpcHaaUXJmxd1/vvvx80TUOtVqOhoQH/+c9/8OSTTyI8PBwVFRXYuXMn5s2bh+rqasTG\nxuLNN9/Em2++iVdeeSUkpQLHx8fxk5/8BBs2bJg0ILJ9T/fu3RuQc1CeIELTtCd/eHhCBpPJRF97\n7bX0Sy+95Nbt8/PzaaVS6edVXRp0dHTQlZWV9M6dO2mLxULL5XL67bffph966CH6sssuo6dPn07/\n8pe/pDUaTbCXSn/44Yd0dnY2HRERQaelpdHXXnstTdM0/fTTT9MxMTF0ZWUl80ehUNA0TdO/+tWv\n6O+++46maZr++c9/Ts+cOZOeNWsWfcMNN9D9/f1Beyw8PuFWnOPLpzwXJDRN45577kFycjI2bdrk\n9DaDg4NMo0hDQwNuu+02dHV1ed3xWlBQgPj4eAiFQohEIjQ2NjqsafXq1di/fz9iYmKwY8cOVFVV\neXVfoQ5FUVAoFMjKynL6/eHhYSQnJ4eEtBwPzzn48inPxcu3336Ld955B7NmzcKcOXMAnB2q7u7u\nBgA88MAD2LNnD7Zs2QKRSITo6Gjs2rXL57m8//znPy4VeD799FPI5XLI5XLU19fjwQcfdFD1uVgQ\nCoUuAyIAXqWI54KFzxR5eNykoKAAjY2NLi/4K1aswMKFC3HHHXcAACQSCQ4dOsScR/F4jytVms7O\nTpSXl0MikQA4L3Rvz+joKG6//XZ0dnaioKAAH3zwAT9Wcenh1o6Yr23w8LiJQCDAtddei+rqavz1\nr391+L4z/VfebZ0biCqNs4ad4uJiHD9+HMePH3caEAFgw4YNjMXT1VdfjQ0bNvh7yTwXKHz5lIfH\nTb755htkZ2djaGgIixYtQllZWUh2VV6MuFKlcZePPvoIhw4dAgDcc889WLhwIZ5//nkOVsZzscFn\nijw8bkK0XNPS0nDzzTejoaHB4ftT6b/ycE9HRwfmzp2LH/3oR/j666+d3kahUDBl7IyMDCgUikAu\nkecCgg+KPDxuoNVqodFomH9//vnnDvNqy5Ytw9tvvw2aplFXV4fExESvzxNbWlowZ84c5k9CQoJD\nl+2hQ4eQmJjI3Oapp57y7sGFCNdccw1mzpzp8Oejjz5y+TOZmZno7u7GsWPHsHHjRtx5551Qq9WT\n3o9AIAgJSy2e0IQvn/LwuIFCocDNN98M4KzKy5133onrrruOOcN64IEHsGTJEuzfvx9isRgxMTF4\n6623vL4/iUSC48ePAzg7/pCdnc3cP5uLSdv1wIEDHv9MZGQko1daXV2N4uJiyGQyBym39PR0Zgh/\nYGAAaWlpnKyZ5+KDD4o8PG5QVFSEEydOOHz9gQceYP4tEAjw6quvcn7fBw8eRHFxMe9A7wSlUonk\n5GQIhUK0t7dDLpejqKjI4XbEoWXt2rXYuXMno4fKw2MPXz7l4Qlxdu3axYx52HPkyBFUVlbi+uuv\nx5kzZwK8ssCxd+9e5OTk4MiRI/jJT36CxYsXAwAOHz6M2bNnY86cObjtttuwdetWJCcnAwDuu+8+\nRmBh7dq1+OKLL1BSUoIDBw5g7dq1QXssPKENP6fIwxPCmEwmZGVl4cyZMw5i22q1GmFhYYy26+rV\nq3ltVx4e1/Bzijw8FzqffvopqqqqHAIiACQkJCAuLg4AsGTJEpjNZgwPDwd6iTw8FxV8UOThCWHe\nf/99l6XTwcFBkEpPQ0MDrFYrUlJSPPr99957L9LS0mw6aUdHR7Fo0SKUlJRg0aJFGBsbc/qzO3fu\nRElJCUpKSrBz506P7peHJ1Thy6c8PCGKVqtFXl4e2tvbkZiYCAA23a6bN2+20XbduHEjLr/8co/u\n4/Dhw4iLi8Pdd9/NeAT+4Q9/QHJyMtauXYsNGzZgbGzMYdB9dHQUNTU1aGxshEAgQHV1NY4ePcpL\np/GEMrzJMA8Pz9TYG+eyNVsHBgawcOFCtLS02PzM+++/j0OHDmHbtm0AHHVfeXhCEP5MkYeHx3Pc\nUX/hdV55Llb4oMjDw+MSXv2F51LD0/IpDw/PRYZAICgA8AlN0zPP/b8FwEKapgcEAkEmgEM0TUvs\nfuaOc7dZce7/287d7v2ALp6Hh2P4TJGHh8eejwHcc+7f9wBwJj76bwDXCgSCaQKBYBqAa899jYfn\ngoYPijw8lzACgeB9AEcASAQCQa9AIPgVgA0AFgkEAjmAa879HwKBoEYgELwOADRNjwJ4GsB35/48\nde5rPDwXNHz5lIeHh4eH5xx8psjDw8PDw3MOPijy8PDw8PCcgw+KPDw8PDw85+CDIg8PDw8Pzzn4\noMjDw8PDw3MOPijy8PDw8PCcgw+KPDw8PDw85/j/dqYFHZm5l0cAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f18ffd58c88>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from matplotlib import cm\n",
    "from mpl_toolkits.mplot3d import Axes3D\n",
    "%matplotlib inline\n",
    "\n",
    "# 可视化结果\n",
    "view_data = Variable((train_set.train_data[:200].type(torch.FloatTensor).view(-1, 28*28) / 255. - 0.5) / 0.5)\n",
    "encode, _ = net(view_data)    # 提取压缩的特征值\n",
    "fig = plt.figure(2)\n",
    "ax = Axes3D(fig)    # 3D 图\n",
    "# x, y, z 的数据值\n",
    "X = encode.data[:, 0].numpy()\n",
    "Y = encode.data[:, 1].numpy()\n",
    "Z = encode.data[:, 2].numpy()\n",
    "values = train_set.train_labels[:200].numpy()  # 标签值\n",
    "for x, y, z, s in zip(X, Y, Z, values):\n",
    "    c = cm.rainbow(int(255*s/9))    # 上色\n",
    "    ax.text(x, y, z, s, backgroundcolor=c)  # 标位子\n",
    "ax.set_xlim(X.min(), X.max())\n",
    "ax.set_ylim(Y.min(), Y.max())\n",
    "ax.set_zlim(Z.min(), Z.max())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到，不同种类的图片进入自动编码器之后会被编码得不同，而相同类型的图片经过自动编码之后的编码在几何示意图上距离较近，在训练好自动编码器之后，我们可以给一个随机的 code，通过 decoder 生成图片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T11:06:02.107432Z",
     "start_time": "2018-01-01T11:06:01.958234Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f18ff145cc0>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\nJpS2SNpQ3N4g6aXGdw9As0zlbf9fSfqupL1m9max7RFJj0v6LzN7UNJRSfc3p4uNkVvOOVefO3du\naW3VqlXJtjfeeGPNzy1Jo6OjyXrqkt5c31auXJmsL1q0KFk/ceJEsv7YY4+V1l555ZVk29ylzKhP\nNvzu/r+SygbJv9nY7gBoFc7wA4Ii/EBQhB8IivADQRF+ICjCDwQVZuru3OWfuUt+U+cBdHZ2Jtsu\nW7YsWV++fHmy3tXVlaynzhPI/XefPXs2Wd+5c2ey/sQTTyTrW7duLa0NDw8n2+aWJkd9OPIDQRF+\nICjCDwRF+IGgCD8QFOEHgiL8QFBhxvlzRkZGkvXU9Nj79+9Ptp03b16ynltqesmSJcn6rFmzSmvH\njh1Ltn355ZeT9RdffDFZP3ToULLOMtrtiyM/EBThB4Ii/EBQhB8IivADQRF+ICjCDwRlrbxmumxJ\nrxa9drI+fXr6lId6rufPXY+fa5/7f3Tu3LnS2uDgpAspTamtJI2NjSXrXHPfftw9/cte4MgPBEX4\ngaAIPxAU4QeCIvxAUIQfCIrwA0Flx/nNbKmkZyQtlOSSNrn7T83sUUnfl3SyeOgj7v7bzHMxKAw0\n2VTH+acS/h5JPe6+y8yulLRT0n2S7pd0xt3/baqdIvxA8001/NmZfNx9QNJAcXvYzA5IWlxf9wBU\n7Ut95jezZZK+Lum1YtNDZrbHzJ42s6tL2mw0sx1mtqOungJoqCmf229mcyW9LOlf3P15M1so6ZTG\nvwf4Z41/NPjbzHPwth9osoZ95pckM+uQ9BtJW939J5PUl0n6jbvflHkewg80WcMu7LHxy+GeknRg\nYvCLLwIvWS9p35ftJIDqTOXb/tslvSJpr6RL6z0/IukBSTdr/G3/EUk/KL4cTD0XR36gyRr6tr9R\nCD/QfFzPDyCJ8ANBEX4gKMIPBEX4gaAIPxAU4QeCIvxAUIQfCIrwA0ERfiAowg8ERfiBoAg/EFR2\nAs8GOyXp6IT73cW2dtSufWvXfkn0rVaN7NufTvWBLb2e/wsvbrbD3Xsr60BCu/atXfsl0bdaVdU3\n3vYDQRF+IKiqw7+p4tdPade+tWu/JPpWq0r6VulnfgDVqfrID6AilYTfzO4ysz+a2WEze7iKPpQx\nsyNmttfM3qx6ibFiGbRBM9s3YVuXmf3BzN4ufk66TFpFfXvUzPqLffemma2rqG9Lzex/zGy/mb1l\nZn9XbK903yX6Vcl+a/nbfjObJumQpDsl9Ul6XdID7r6/pR0pYWZHJPW6e+Vjwmb215LOSHrm0mpI\nZvavkobc/fHiD+fV7v4PbdK3R/UlV25uUt/KVpb+nircd41c8boRqjjyr5V02N3fdfcRSb+SdG8F\n/Wh77r5d0tDnNt8raXNxe7PGf3larqRvbcHdB9x9V3F7WNKllaUr3XeJflWiivAvlnRswv0+tdeS\n3y7p92a208w2Vt2ZSSycsDLScUkLq+zMJLIrN7fS51aWbpt9V8uK143GF35fdLu7/4WkuyX9sHh7\n25Z8/DNbOw3X/EzSCo0v4zYg6cdVdqZYWfo5ST9y948n1qrcd5P0q5L9VkX4+yUtnXB/SbGtLbh7\nf/FzUNILGv+Y0k5OXFoktfg5WHF//p+7n3D3MXf/VNLPVeG+K1aWfk7SL939+WJz5ftusn5Vtd+q\nCP/rklaa2XIzmyHpO5K2VNCPLzCzzuKLGJlZp6Rvqf1WH94iaUNxe4Oklyrsy2e0y8rNZStLq+J9\n13YrXrt7y/9JWqfxb/zfkfSPVfShpF/XS9pd/Hur6r5JelbjbwNHNf7dyIOSrpG0TdLbkv5bUlcb\n9e0/NL6a8x6NB62nor7drvG39HskvVn8W1f1vkv0q5L9xhl+QFB84QcERfiBoAg/EBThB4Ii/EBQ\nhB8IivADQRF+IKj/A6nyKozZdG0BAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f18ff288dd8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "code = Variable(torch.FloatTensor([[1.19, -3.36, 2.06]])) # 给一个 code 是 (1.19, -3.36, 2.06)\n",
    "decode = net.decoder(code)\n",
    "decode_img = to_img(decode).squeeze()\n",
    "decode_img = decode_img.data.numpy() * 255\n",
    "plt.imshow(decode_img.astype('uint8'), cmap='gray') # 生成图片 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里我们仅仅使用多层神经网络定义了一个自动编码器，当然你会想到，为什么不使用效果更好的卷积神经网络呢？我们当然可以使用卷积神经网络来定义，下面我们就重新定义一个卷积神经网络来进行 autoencoder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T11:06:06.346907Z",
     "start_time": "2018-01-01T11:06:06.284342Z"
    },
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class conv_autoencoder(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(conv_autoencoder, self).__init__()\n",
    "        \n",
    "        self.encoder = nn.Sequential(\n",
    "            nn.Conv2d(1, 16, 3, stride=3, padding=1),  # (b, 16, 10, 10)\n",
    "            nn.ReLU(True),\n",
    "            nn.MaxPool2d(2, stride=2),  # (b, 16, 5, 5)\n",
    "            nn.Conv2d(16, 8, 3, stride=2, padding=1),  # (b, 8, 3, 3)\n",
    "            nn.ReLU(True),\n",
    "            nn.MaxPool2d(2, stride=1)  # (b, 8, 2, 2)\n",
    "        )\n",
    "        \n",
    "        self.decoder = nn.Sequential(\n",
    "            nn.ConvTranspose2d(8, 16, 3, stride=2),  # (b, 16, 5, 5)\n",
    "            nn.ReLU(True),\n",
    "            nn.ConvTranspose2d(16, 8, 5, stride=3, padding=1),  # (b, 8, 15, 15)\n",
    "            nn.ReLU(True),\n",
    "            nn.ConvTranspose2d(8, 1, 2, stride=2, padding=1),  # (b, 1, 28, 28)\n",
    "            nn.Tanh()\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        encode = self.encoder(x)\n",
    "        decode = self.decoder(encode)\n",
    "        return encode, decode"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T11:06:10.043014Z",
     "start_time": "2018-01-01T11:06:06.944171Z"
    },
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "conv_net = conv_autoencoder()\n",
    "if torch.cuda.is_available():\n",
    "    conv_net = conv_net.cuda()\n",
    "optimizer = torch.optim.Adam(conv_net.parameters(), lr=1e-3, weight_decay=1e-5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于卷积网络中，我们可以对输入进行上采样，那么对于卷积神经网络，我们可以使用转置卷积进行这个操作，这里我们先不展开讨论转置卷积，如果想先了解转置卷积，可以看看[语义分割](https://github.com/SherlockLiao/code-of-learn-deep-learning-with-pytorch/blob/master/chapter9_Computer-Vision/segmentation/fcn.ipynb)的部分，里面有转置卷积的介绍\n",
    "\n",
    "在 pytorch 中使用转置卷积就是上面的操作，`torch.nn.ConvTranspose2d()` 就可以了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-01-01T11:15:44.595927Z",
     "start_time": "2018-01-01T11:06:24.760698Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 20, Loss: 101.2340\n",
      "epoch: 40, Loss: 86.2428\n"
     ]
    }
   ],
   "source": [
    "# 开始训练自动编码器\n",
    "for e in range(40):\n",
    "    for im, _ in train_data:\n",
    "        if torch.cuda.is_available():\n",
    "            im = im.cuda()\n",
    "        im = Variable(im)\n",
    "        # 前向传播\n",
    "        _, output = conv_net(im)\n",
    "        loss = criterion(output, im) / im.shape[0] # 平均\n",
    "        # 反向传播\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "    \n",
    "    if (e+1) % 20 == 0: # 每 20 次，将生成的图片保存一下\n",
    "        print('epoch: {}, Loss: {:.4f}'.format(e+1, loss.data[0]))\n",
    "        pic = to_img(output.cpu().data)\n",
    "        if not os.path.exists('./conv_autoencoder'):\n",
    "            os.mkdir('./conv_autoencoder')\n",
    "        save_image(pic, './conv_autoencoder/image_{}.png'.format(e+1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为了时间更短，只跑 40 次，如果有条件可以再 gpu 上跑跑\n",
    "\n",
    "最后我们看看结果\n",
    "\n",
    "![](https://ws1.sinaimg.cn/large/006tNc79ly1fmzww48to3j306q0a20ud.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里我们展示了简单的自动编码器，也用了多层神经网络和卷积神经网络作为例子，但是自动编码器存在一个问题，我们并不能任意生成我们想要的数据，因为我们并不知道 encode 之后的编码到底是什么样的概率分布，所以有一个改进的版本变分自动编码器，其能够解决这个问题"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
